chore: import upstream snapshot with attribution
This commit is contained in:
Executable
+124
@@ -0,0 +1,124 @@
|
||||
#!/usr/bin/env bash
|
||||
# Watch a single GPU for foreign processes (anyone other than the current
|
||||
# user) appearing during a long-running test. Intended companion to
|
||||
# `/tir-test`: leave this running in a side terminal while pytest runs, and
|
||||
# it will alert if someone else lands on the same GPU.
|
||||
#
|
||||
# Usage:
|
||||
# monitor_gpu.sh # uses $CUDA_VISIBLE_DEVICES, defaults to 0
|
||||
# monitor_gpu.sh --gpu 3 # watch GPU 3
|
||||
# monitor_gpu.sh --gpu 3 --interval 2 # poll every 2 seconds
|
||||
# monitor_gpu.sh --log /tmp/gpu.log # also tee to a log file
|
||||
|
||||
# Note: deliberately not `set -u` — bash <5.2 errors on `${#assoc[@]}` when
|
||||
# the associative array is empty.
|
||||
|
||||
GPU=""
|
||||
INTERVAL=5
|
||||
LOG=""
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--gpu) GPU="$2"; shift 2 ;;
|
||||
--interval) INTERVAL="$2"; shift 2 ;;
|
||||
--log) LOG="$2"; shift 2 ;;
|
||||
-h|--help)
|
||||
sed -n '2,12p' "$0" | sed 's/^# \{0,1\}//'
|
||||
exit 0 ;;
|
||||
*) echo "unknown arg: $1" >&2; exit 2 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [[ -z "$GPU" ]]; then
|
||||
GPU="${CUDA_VISIBLE_DEVICES:-0}"
|
||||
fi
|
||||
# Only the first index if CUDA_VISIBLE_DEVICES is a list.
|
||||
GPU="${GPU%%,*}"
|
||||
if ! [[ "$GPU" =~ ^[0-9]+$ ]]; then
|
||||
echo "monitor_gpu: GPU must be an integer index (got '$GPU'); pass --gpu <n>" >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
ME="$(id -un)"
|
||||
|
||||
emit() {
|
||||
local line="[$(date +'%H:%M:%S')] $*"
|
||||
if [[ -n "$LOG" ]]; then
|
||||
printf '%s\n' "$line" | tee -a "$LOG" >&2
|
||||
else
|
||||
printf '%s\n' "$line" >&2
|
||||
fi
|
||||
}
|
||||
|
||||
# Returns "pid|user|mem_mib|process_name" lines for compute apps on $GPU.
|
||||
snapshot() {
|
||||
nvidia-smi --id="$GPU" \
|
||||
--query-compute-apps=pid,process_name,used_memory \
|
||||
--format=csv,noheader,nounits 2>/dev/null \
|
||||
| while IFS=, read -r pid pname mem; do
|
||||
pid="${pid// /}"
|
||||
[[ -z "$pid" ]] && continue
|
||||
local user
|
||||
user="$(ps -o user= -p "$pid" 2>/dev/null | tr -d ' ')"
|
||||
[[ -z "$user" ]] && user="?"
|
||||
pname="${pname# }"
|
||||
mem="${mem# }"
|
||||
printf '%s|%s|%s|%s\n' "$pid" "$user" "$mem" "$pname"
|
||||
done
|
||||
}
|
||||
|
||||
emit "monitor_gpu started: GPU=$GPU interval=${INTERVAL}s user=$ME"
|
||||
|
||||
declare -A KNOWN # pid -> "user|mem|pname"
|
||||
|
||||
# Initial snapshot — record everyone we already see as the baseline.
|
||||
while IFS='|' read -r pid user mem pname; do
|
||||
[[ -z "${pid:-}" ]] && continue
|
||||
KNOWN[$pid]="$user|$mem|$pname"
|
||||
flag=""
|
||||
[[ "$user" != "$ME" ]] && flag=" [FOREIGN]"
|
||||
emit "baseline pid=$pid user=$user mem=${mem}MiB cmd=$pname$flag"
|
||||
done < <(snapshot)
|
||||
|
||||
if [[ ${#KNOWN[@]} -eq 0 ]]; then
|
||||
emit "baseline: GPU $GPU is idle"
|
||||
fi
|
||||
|
||||
trap 'emit "monitor_gpu stopped"; exit 0' INT TERM
|
||||
|
||||
heartbeat_due=$(( $(date +%s) + 60 ))
|
||||
|
||||
while :; do
|
||||
sleep "$INTERVAL"
|
||||
|
||||
declare -A SEEN=()
|
||||
while IFS='|' read -r pid user mem pname; do
|
||||
[[ -z "${pid:-}" ]] && continue
|
||||
SEEN[$pid]=1
|
||||
if [[ -z "${KNOWN[$pid]:-}" ]]; then
|
||||
flag=""
|
||||
[[ "$user" != "$ME" ]] && flag=" *** FOREIGN USER ***"
|
||||
emit "NEW pid=$pid user=$user mem=${mem}MiB cmd=$pname$flag"
|
||||
KNOWN[$pid]="$user|$mem|$pname"
|
||||
fi
|
||||
done < <(snapshot)
|
||||
|
||||
for pid in "${!KNOWN[@]}"; do
|
||||
if [[ -z "${SEEN[$pid]:-}" ]]; then
|
||||
emit "GONE pid=$pid (was: ${KNOWN[$pid]})"
|
||||
unset 'KNOWN[$pid]'
|
||||
fi
|
||||
done
|
||||
unset SEEN
|
||||
|
||||
now=$(date +%s)
|
||||
if (( now >= heartbeat_due )); then
|
||||
foreign=0
|
||||
for v in "${KNOWN[@]}"; do
|
||||
u="${v%%|*}"
|
||||
[[ "$u" != "$ME" ]] && foreign=$((foreign+1))
|
||||
done
|
||||
emit "heartbeat: ${#KNOWN[@]} process(es) on GPU $GPU (${foreign} foreign)"
|
||||
heartbeat_due=$(( now + 60 ))
|
||||
fi
|
||||
done
|
||||
@@ -0,0 +1,17 @@
|
||||
Build TVM from the current worktree.
|
||||
|
||||
## Steps
|
||||
|
||||
1. Check that `build/` directory exists. If not, run initial setup:
|
||||
```bash
|
||||
mkdir -p build
|
||||
cmake -S . -B build
|
||||
cmake --build build --parallel
|
||||
```
|
||||
|
||||
2. If `build/` already exists, run incremental build:
|
||||
```bash
|
||||
cmake --build build --parallel
|
||||
```
|
||||
|
||||
3. Report success/failure and build time.
|
||||
@@ -0,0 +1,59 @@
|
||||
Run the full TIRX test suite.
|
||||
|
||||
## Steps
|
||||
|
||||
1. Install the kernel package and select the least busy GPU:
|
||||
```bash
|
||||
pip install -e /path/to/tirx-kernels-staging # or sibling tirx-kernels checkout
|
||||
export CUDA_VISIBLE_DEVICES=$(nvidia-smi --query-gpu=index,memory.used --format=csv,noheader,nounits | sort -t',' -k2 -n | head -1 | cut -d',' -f1 | tr -d ' ')
|
||||
export TVM_PATH=/path/to/tvm
|
||||
export PYTHONPATH="${TVM_PATH}/python"
|
||||
export TVM_LIBRARY_PATH="${TVM_PATH}/build/lib"
|
||||
```
|
||||
|
||||
2. Start the GPU monitor in the background so we can detect if anyone else lands on the same GPU mid-run:
|
||||
```bash
|
||||
GPU_LOG="/tmp/tir_test_gpu_${CUDA_VISIBLE_DEVICES}.log"
|
||||
bash .agents/scripts/monitor_gpu.sh --gpu "$CUDA_VISIBLE_DEVICES" --interval 5 --log "$GPU_LOG" &
|
||||
MON_PID=$!
|
||||
trap 'kill $MON_PID 2>/dev/null' EXIT
|
||||
```
|
||||
|
||||
3. Import gate — bench workloads: fail fast if any kernel listed in `workloads.yaml` fails to import:
|
||||
```bash
|
||||
python -m tirx_kernels.bench_suite --check-imports
|
||||
```
|
||||
A non-zero exit means a pinned workload kernel failed to import — fix it before proceeding.
|
||||
|
||||
4. Full kernel import gate (correctness test suite coverage):
|
||||
```bash
|
||||
python -m tirx_kernels.registry --cc 10 --strict
|
||||
```
|
||||
|
||||
5. Run the full test suite with xdist parallelism:
|
||||
```bash
|
||||
pytest tests/python/tirx/ -n 16
|
||||
```
|
||||
|
||||
6. Stop the monitor and check for foreign GPU usage during the run:
|
||||
```bash
|
||||
kill $MON_PID 2>/dev/null; wait $MON_PID 2>/dev/null
|
||||
grep -E 'FOREIGN USER|\[FOREIGN\]' "$GPU_LOG" || echo "no foreign GPU usage observed"
|
||||
```
|
||||
|
||||
7. Report results: total passed, failed, skipped, errors — and the import-gate results from steps 3–4. If any foreign-user events are present in step 6, mention them — flaky failures should be re-evaluated on a clean GPU before being attributed to code changes.
|
||||
|
||||
## Failure triage rules
|
||||
|
||||
**CRITICAL: Never pipe test output to `tail` or `grep` when diagnosing failures. Always capture and read full logs.**
|
||||
|
||||
Classify every failure into one of these categories:
|
||||
|
||||
- **A — Environment/import error**: Module not found, missing dependency, collection error. These are not caused by code changes.
|
||||
- **B — Real kernel correctness regression**: Assertion failures (cosine_sim, numerical diff), `CUDA: unspecified launch failure`, or wrong results. **These MUST be investigated and fixed if caused by current changes.**
|
||||
- **C — Secondary xdist crash**: `KeyError: <WorkerController gwXX>` after a worker abort. The KeyError itself is noise — find the underlying cause (usually category B in another worker).
|
||||
|
||||
**Never dismiss a failure as "pre-existing" without evidence.** If a test fails:
|
||||
1. Check whether the test touches code you changed.
|
||||
2. If unclear, verify on the parent commit before claiming pre-existing.
|
||||
3. All failures caused by current changes MUST be fixed — not deferred.
|
||||
@@ -0,0 +1,89 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
github:
|
||||
description: "Open Machine Learning Compiler Framework"
|
||||
homepage: https://tvm.apache.org/
|
||||
labels:
|
||||
- tvm
|
||||
- compiler
|
||||
- tensor
|
||||
- deep-learning
|
||||
- gpu
|
||||
- opencl
|
||||
- metal
|
||||
- performance
|
||||
- javascript
|
||||
- rocm
|
||||
- vulkan
|
||||
- spirv
|
||||
- machine-learning
|
||||
|
||||
features:
|
||||
# Enable issue management
|
||||
issues: true
|
||||
# Enable projects for project management boards
|
||||
projects: true
|
||||
|
||||
# Triage perm for collaborators(test run)
|
||||
#
|
||||
# The perm is given based on needs and not based on
|
||||
# evaluation of past contributions. The rationale
|
||||
# is that people may need the permission to start
|
||||
# contributing in this way. It serves to diversify
|
||||
# the ways to contribute.
|
||||
#
|
||||
# There is a limited number of slots. To enable broad
|
||||
# participation, permission is given on a three month
|
||||
# cycle. PMC may review and recycle slots when necessary.
|
||||
collaborators:
|
||||
- tvm-bot # For automated feedback in PR review.
|
||||
|
||||
# See https://cwiki.apache.org/confluence/display/INFRA/Git+-+.asf.yaml+features#Git.asf.yamlfeatures-Branchprotection
|
||||
protected_branches:
|
||||
main:
|
||||
required_status_checks:
|
||||
contexts:
|
||||
- arm/pr-head
|
||||
- cpu/pr-head
|
||||
- docker/pr-head
|
||||
- gpu/pr-head
|
||||
- wasm/pr-head
|
||||
|
||||
required_pull_request_reviews:
|
||||
required_approving_review_count: 1
|
||||
|
||||
enabled_merge_buttons:
|
||||
# enable squash button:
|
||||
squash: true
|
||||
# default commit message when merging with a squash commit
|
||||
# can either be: DEFAULT | PR_TITLE | PR_TITLE_AND_COMMIT_DETAILS | PR_TITLE_AND_DESC
|
||||
squash_commit_message: PR_TITLE_AND_DESC
|
||||
# enable merge button:
|
||||
merge: false
|
||||
# default commit message when merging with a merge commit
|
||||
# can either be: DEFAULT | PR_TITLE | PR_TITLE_AND_DESC
|
||||
merge_commit_message: DEFAULT
|
||||
# enable rebase button for rare use.
|
||||
rebase: true
|
||||
|
||||
notifications:
|
||||
commits: commits@tvm.apache.org
|
||||
issues: discuss-archive@tvm.apache.org
|
||||
pullrequests: discuss-archive@tvm.apache.org
|
||||
jobs: discuss-archive@tvm.apache.org
|
||||
discussions: discuss-archive@tvm.apache.org
|
||||
@@ -0,0 +1,8 @@
|
||||
# Run the following command to reformat a file:
|
||||
# clang-format -i -style=Google <file>
|
||||
# Or use clang-format-diff to only reformat the changed lines:
|
||||
# https://clang.llvm.org/docs/ClangFormat.html
|
||||
BasedOnStyle: Google
|
||||
DerivePointerAlignment: false
|
||||
ColumnLimit: 100
|
||||
PointerAlignment: Left
|
||||
@@ -0,0 +1,2 @@
|
||||
Jenkinsfile linguist-generated=true
|
||||
ci/jenkins/generated/* linguist-generated=true
|
||||
@@ -0,0 +1,162 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
# GitHub code owners file
|
||||
# This file is used as a convenient tool to map
|
||||
# committers' areas of expertise and faciliate the review process.
|
||||
#
|
||||
# This may not be the non-comprehensive list and is meant to be
|
||||
# updated over time.
|
||||
|
||||
# Per ASF policy, committer have global write permission.
|
||||
# We normally recommend committers to shepherd code in their area of expertise.
|
||||
* @apache/tvm-committers
|
||||
|
||||
# Order is important; the last matching pattern takes the most precedence.
|
||||
# The sub modules should be ordered first by depth.
|
||||
# Making sure we append new sub-module rules after exisiting modules rules.
|
||||
|
||||
###############################################################################
|
||||
# IMPORTANT NOTE
|
||||
# This file is intentionally not named CODEOWNERS to avoid getting picked up
|
||||
# by GitHub's code owners -> review mechanism. For details see
|
||||
# https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners
|
||||
# and https://github.com/apache/tvm-rfcs/pull/58
|
||||
#
|
||||
# This file is kept to allow manual inspection of who is responsible for
|
||||
# different segments of the codebase.
|
||||
###############################################################################
|
||||
|
||||
##############################
|
||||
# Top-level Fallbacks
|
||||
##############################
|
||||
include/** @tqchen @jroesch @yzhliu @icemelon @junrushao1994 @comaniac @zhiics
|
||||
src/** @tqchen @jroesch @yzhliu @icemelon @junrushao1994 @comaniac @zhiics
|
||||
apps/** @tqchen @jroesch @yzhliu @icemelon @junrushao1994 @comaniac @zhiics
|
||||
python/** @tqchen @jroesch @yzhliu @icemelon @junrushao1994 @comaniac @zhiics
|
||||
|
||||
# Thirdparty license audit
|
||||
3rdparty/** @tqchen @jroesch
|
||||
licenses/** @tqchen @jroesch
|
||||
|
||||
# JVM language
|
||||
jvm/** @yzhliu
|
||||
|
||||
# Golang
|
||||
golang/** @srkreddy1238
|
||||
|
||||
# WASM
|
||||
web/** @tqchen @jroesch
|
||||
|
||||
# Docker
|
||||
docker/** @areusch @leandron @jroesch
|
||||
|
||||
# Conda
|
||||
tests/conda/** @tqchen @junrushao1994 @comaniac
|
||||
|
||||
# CMake
|
||||
cmake/** @jroesch @tqchen @areusch @junrushao1994 @comaniac
|
||||
|
||||
# rust bindings
|
||||
rust/** @jroesch @nhynes @nhynes
|
||||
|
||||
# vta
|
||||
vta/** @tmoreau89 @vegaluisjose
|
||||
|
||||
# docs
|
||||
docs/** @comaniac @junrushao1994 @tqchen @jroesch @areusch @yzhliu @merrymercy @icemelon
|
||||
tutorials/** @comaniac @junrushao1994 @tqchen @jroesch @areusch @yzhliu @merrymercy @icemelon
|
||||
|
||||
# tests
|
||||
tests/** @comaniac @junrushao1994 @tqchen @jroesch @areusch @yzhliu @merrymercy @icemelon
|
||||
|
||||
##############################
|
||||
# Specific modules
|
||||
##############################
|
||||
|
||||
# automation related
|
||||
src/auto_scheduler/** @merrymercy @jcf94 @comaniac @junrushao1994 @vinx13 @Hzfengsy
|
||||
include/tvm/auto_scheduler/** @merrymercy @jcf94 @comaniac @junrushao1994 @vinx13 @Hzfengsy
|
||||
python/tvm/auto_scheduler/** @merrymercy @jcf94 @comaniac @junrushao1994 @vinx13 @Hzfengsy
|
||||
|
||||
python/tvm/autotvm/** @merrymercy @jcf94 @comaniac @junrushao1994 @vinx13
|
||||
|
||||
# node system and reflection
|
||||
src/node/** @junrushao1994 @vinx13 @tqchen @jroesch @comaniac
|
||||
include/tvm/node/** @junrushao1994 @vinx13 @tqchen @jroesch @comaniac
|
||||
|
||||
# ir: Common IR
|
||||
src/ir/** @junrushao1994 @vinx13 @tqchen @jroesch @comaniac
|
||||
include/tvm/ir/** @junrushao1994 @vinx13 @tqchen @jroesch @comaniac
|
||||
python/tvm/ir/** @junrushao1994 @vinx13 @tqchen @jroesch @comaniac
|
||||
|
||||
# tir
|
||||
src/tir/** @junrushao1994 @vinx13 @tqchen @kparzysz-quic @ZihengJiang @masahi @were @Hzfengsy
|
||||
include/tvm/tir/** @junrushao1994 @vinx13 @tqchen @kparzysz-quic @ZihengJiang @masahi @were @Hzfengsy
|
||||
python/tvm/tir/** @junrushao1994 @vinx13 @tqchen @kparzysz-quic @ZihengJiang @masahi @were @Hzfengsy
|
||||
|
||||
# te
|
||||
src/te/** @junrushao1994 @vinx13 @tqchen @kparzysz-quic @ZihengJiang @masahi @were
|
||||
include/tvm/te/** @junrushao1994 @vinx13 @tqchen @kparzysz-quic @ZihengJiang @masahi @were
|
||||
python/tvm/te/** @junrushao1994 @vinx13 @tqchen @kparzysz-quic @ZihengJiang @masahi @were
|
||||
|
||||
# target
|
||||
src/target/** @junrushao1994 @vinx13 @tqchen @kparzysz-quic @ZihengJiang @masahi
|
||||
include/tvm/target/** @junrushao1994 @vinx13 @tqchen @kparzysz-quic @ZihengJiang @masahi
|
||||
python/tvm/target/** @junrushao1994 @vinx13 @tqchen @kparzysz-quic @ZihengJiang @masahi
|
||||
|
||||
# arith: Arithmetic module and simplifiers
|
||||
src/arith/** @tqchen @junrushao1994 @vinx13
|
||||
include/tvm/arith/** @tqchen @junrushao1994 @vinx13
|
||||
python/tvm/arith/** @tqchen @junrushao1994 @vinx13
|
||||
|
||||
# parser
|
||||
src/parser/** @jroesch @slyubomirsky
|
||||
|
||||
# runtime
|
||||
src/runtime/** @vinx13 @tqchen @FronzenGene @liangfu @areusch @tmoreau89 @ajtulloch @masahi @kazum @ZihengJiang @junrushao1994
|
||||
include/tvm/runtime/** @vinx13 @tqchen @FronzenGene @liangfu @areusch @tmoreau89 @ajtulloch @masahi @kazum @ZihengJiang @junrushao1994
|
||||
python/tvm/runtime/** @vinx13 @tqchen @FronzenGene @liangfu @areusch @tmoreau89 @ajtulloch @masahi @kazum @ZihengJiang @junrushao1994
|
||||
|
||||
# relay
|
||||
src/relay/** @jroesch @slyubomirsky @icemelon @MarisaKirisame @ZihengJiang @yzhliu @vinx13 @mbrookhart @jwfromm @zhiics @anijain2305 @wweic @eqy @junrushao1994
|
||||
include/tvm/relay/** @jroesch @slyubomirsky @icemelon @MarisaKirisame @ZihengJiang @yzhliu @vinx13 @mbrookhart @jwfromm @zhiics @anijain2305 @wweic @eqy @junrushao1994
|
||||
python/tvm/relay/** @jroesch @slyubomirsky @icemelon @MarisaKirisame @ZihengJiang @yzhliu @vinx13 @mbrookhart @jwfromm @zhiics @anijain2305 @wweic @eqy @junrushao1994
|
||||
|
||||
|
||||
# relay/qnn
|
||||
src/relay/qnn/** @jwfromm @anijain2305 @ZihengJiang
|
||||
inlcude/tvm/relay/qnn/** @jwfromm @anijain2305 @ZihengJiang
|
||||
python/tvm/relay/qnn/** @jwfromm @anijain2305 @ZihengJiang
|
||||
|
||||
# relay/backend/contrib: BYOC
|
||||
src/relay/backend/contrib/** @zhiics @trevor-m @comaniac @mbaret @manupa-arm
|
||||
|
||||
# relay/frontends
|
||||
python/tvm/relay/frontend/** @jwfromm @mbrookhart @srkreddy1238 @siju-samuel @Huyuwei @hlu1 @kazum @PariksheetPinjari909
|
||||
|
||||
# topi: Operator definitions
|
||||
src/topi/** @Laurawly @Huyuwei @kevinthesun @jwfromm @vinx13 @masahi @FronzenGene @yzhliu @mbrookhart @ZihengJiang @jcf94
|
||||
include/tvm/topi/** @Laurawly @Huyuwei @kevinthesun @jwfromm @vinx13 @masahi @FronzenGene @yzhliu @mbrookhart @ZihengJiang @jcf94
|
||||
python/tvm/topi/** @Laurawly @Huyuwei @kevinthesun @jwfromm @vinx13 @masahi @FronzenGene @yzhliu @mbrookhart @ZihengJiang @jcf94
|
||||
|
||||
|
||||
# tvm/driver/
|
||||
python/tvm/driver/** @leandron @jwfromm @tqchen @jroesch
|
||||
|
||||
# tvm/driver/tvmc
|
||||
python/tvm/driver/tvmc/** @leandron @jwfromm
|
||||
@@ -0,0 +1,32 @@
|
||||
---
|
||||
name: "\U0001F41B Bug report"
|
||||
about: Please include a description of your environment, preferably a minimum script to reproduce the problem. Find the list of label tags at https://github.com/apache/tvm/labels.
|
||||
title: "[Bug] "
|
||||
labels: "needs-triage, type: bug"
|
||||
---
|
||||
|
||||
Thanks for participating in the TVM community! We use https://discuss.tvm.apache.org/ for any general usage questions and discussions. The issue tracker is used for actionable items such as feature proposals discussion, roadmaps, and bug tracking. You are always welcomed to post on the forum first :smile_cat:
|
||||
|
||||
Issues that are inactive for a period of time may get closed. We adopt this policy so that we won't lose track of actionable issues that may fall at the bottom of the pile. Feel free to reopen a new one if you feel there is an additional problem that needs attention when an old one gets closed.
|
||||
|
||||
### Expected behavior
|
||||
|
||||
What you were expecting
|
||||
|
||||
### Actual behavior
|
||||
|
||||
What actually happened
|
||||
|
||||
### Environment
|
||||
|
||||
Any environment details, such as: Operating System, TVM version, etc
|
||||
|
||||
### Steps to reproduce
|
||||
|
||||
Preferably a minimal script to cause the issue to occur.
|
||||
|
||||
### Triage
|
||||
|
||||
Please refer to the list of label tags [here](https://github.com/apache/tvm/labels) to find the relevant tags and add them below in a bullet format (example below).
|
||||
|
||||
* needs-triage
|
||||
@@ -0,0 +1,28 @@
|
||||
---
|
||||
name: "\U0000274C CI Problem"
|
||||
about: To help the developers act on these problems, please give us as many details of the CI failure as possible. Find the list of label tags at https://github.com/apache/tvm/labels.
|
||||
title: "[CI Problem] "
|
||||
labels: "needs-triage, type:ci"
|
||||
---
|
||||
|
||||
Thanks for participating in the TVM community! We use https://discuss.tvm.apache.org/ for any general usage questions and discussions. The issue tracker is used for actionable items such as feature proposals discussion, roadmaps, and bug tracking. You are always welcomed to post on the forum first :smile_cat:
|
||||
|
||||
Issues that are inactive for a period of time may get closed. We adopt this policy so that we won't lose track of actionable issues that may fall at the bottom of the pile. Feel free to reopen a new one if you feel there is an additional problem that needs attention when an old one gets closed.
|
||||
|
||||
### Branch/PR Failing
|
||||
|
||||
Please provide a link to the PR that has failed to run CI.
|
||||
|
||||
### Jenkins Link
|
||||
|
||||
Provide a link to the specific run that has failed.
|
||||
|
||||
### Flakiness
|
||||
|
||||
Have you seen this multiple times in this branch or in other branches?
|
||||
|
||||
### Triage
|
||||
|
||||
Please refer to the list of label tags [here](https://github.com/apache/tvm/labels) to find the relevant tags and add them below in a bullet format (example below).
|
||||
|
||||
* needs-triage
|
||||
@@ -0,0 +1,5 @@
|
||||
blank_issues_enabled: false # default: true
|
||||
contact_links:
|
||||
- name: 💬 Discourse
|
||||
url: https://discuss.tvm.apache.org/
|
||||
about: Thanks for participating in the TVM community! We use https://discuss.tvm.apache.org/ for any general usage questions and discussions. The issue tracker is used for actionable items such as feature proposals discussion, roadmaps, and bug tracking. You are always welcomed to post on the forum first 😺
|
||||
@@ -0,0 +1,26 @@
|
||||
---
|
||||
name: "\U0001F4C4 Documentation"
|
||||
about: Use this template to suggest additions and changes to the documentation. Find the list of label tags at https://github.com/apache/tvm/labels.
|
||||
title: "[Docs] "
|
||||
labels: "needs-triage, type: doc"
|
||||
---
|
||||
|
||||
Thanks for participating in the TVM community! We use https://discuss.tvm.apache.org/ for any general usage questions and discussions. The issue tracker is used for actionable items such as feature proposals discussion, roadmaps, and bug tracking. You are always welcomed to post on the forum first :smile_cat:
|
||||
|
||||
Issues that are inactive for a period of time may get closed. We adopt this policy so that we won't lose track of actionable issues that may fall at the bottom of the pile. Feel free to reopen a new one if you feel there is an additional problem that needs attention when an old one gets closed.
|
||||
|
||||
### Documentation Title & Type
|
||||
|
||||
Include the title of the document (e.g. "Getting Started with TVM"), and the type of documentation (e.g. user docs, developer docs, tutorials)
|
||||
|
||||
### Additions/Changes Requested
|
||||
|
||||
If an RFC/discuss post exists, link it here.
|
||||
|
||||
Otherwise, specify what actions should be taken to provide additional clarity/readability/reproducibility to the document. Include code snippets from the previous documentation if applicable.
|
||||
|
||||
### Triage
|
||||
|
||||
Please refer to the list of label tags [here](https://github.com/apache/tvm/labels) to find the relevant tags and add them below in a bullet format (example below).
|
||||
|
||||
* needs-triage
|
||||
@@ -0,0 +1,19 @@
|
||||
---
|
||||
name: "\U0001F527 Feature Tracking"
|
||||
about: List clear, small actionable items so we can track the progress of the change. Find the list of label tags at https://github.com/apache/tvm/labels.
|
||||
title: "[Tracking Issue] "
|
||||
labels: "needs-triage, type:rfc-tracking"
|
||||
---
|
||||
|
||||
Thanks for participating in the TVM community! We use https://discuss.tvm.apache.org/ for any general usage questions and discussions. The issue tracker is used for actionable items such as feature proposals discussion, roadmaps, and bug tracking. You are always welcomed to post on the forum first :smile_cat:
|
||||
|
||||
Issues that are inactive for a period of time may get closed. We adopt this policy so that we won't lose track of actionable issues that may fall at the bottom of the pile. Feel free to reopen a new one if you feel there is an additional problem that needs attention when an old one gets closed.
|
||||
|
||||
### This issue is to track progress for FEATURE NAME
|
||||
- [ ] P1. Title of this piece of the feature (PR link if available)
|
||||
|
||||
### Triage
|
||||
|
||||
Please refer to the list of label tags [here](https://github.com/apache/tvm/labels) to find the relevant tags and add them below in a bullet format (example below).
|
||||
|
||||
* needs-triage
|
||||
@@ -0,0 +1,24 @@
|
||||
---
|
||||
name: "\U00002744 Flaky Test"
|
||||
about: Report flaky tests, make sure to include link to CI runs, a sample failure log, and the name of the test(s). Find the list of label tags at https://github.com/apache/tvm/labels.
|
||||
title: "[Flaky Test] "
|
||||
labels: "needs-triage, test: flaky"
|
||||
---
|
||||
|
||||
Thanks for participating in the TVM community! We use https://discuss.tvm.apache.org/ for any general usage questions and discussions. The issue tracker is used for actionable items such as feature proposals discussion, roadmaps, and bug tracking. You are always welcomed to post on the forum first :smile_cat:
|
||||
|
||||
These tests were found to be flaky (intermittently failing on `main` or failed in a PR with unrelated changes). As per [the docs](https://github.com/apache/tvm/blob/main/docs/contribute/ci.rst#handling-flaky-failures), these failures will be disabled in a PR that references this issue until the test owners can fix the source of the flakiness.
|
||||
|
||||
### Test(s)
|
||||
|
||||
- `tests/python/some_file.py::the_test_name`
|
||||
|
||||
### Jenkins Links
|
||||
|
||||
- Please provide link(s) to failed CI runs. If runs are for a PR, explain why your PR did not break the test (e.g. did not touch that part of the codebase)
|
||||
|
||||
### Triage
|
||||
|
||||
Please refer to the list of label tags [here](https://github.com/apache/tvm/labels) to find the relevant tags and add them below in a bullet format (example below).
|
||||
|
||||
* needs-triage
|
||||
@@ -0,0 +1,148 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
name: Build TVM Wheel
|
||||
description: >
|
||||
Build and test the LLVM-enabled TVM wheel for a given OS/architecture
|
||||
combination using cibuildwheel.
|
||||
|
||||
inputs:
|
||||
arch:
|
||||
description: "Target architecture for cibuildwheel (e.g., x86_64, aarch64, arm64, AMD64)"
|
||||
required: true
|
||||
build:
|
||||
description: "cibuildwheel build selector (e.g., cp310-manylinux_x86_64)"
|
||||
required: true
|
||||
cmake_defines:
|
||||
description: "Feature CMake defines that vary by wheel (e.g. -DUSE_METAL=ON on macOS)"
|
||||
required: false
|
||||
default: ""
|
||||
include_cuda_runtime:
|
||||
description: "Set to 1 to build and inject the CUDA runtime library (Linux only)"
|
||||
required: false
|
||||
default: "0"
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
# Single source of truth for the LLVM toolchain version, shared by the cache
|
||||
# key and the conda install steps below.
|
||||
- name: Set LLVM version
|
||||
shell: bash
|
||||
run: echo "LLVM_VERSION=22.1.0" >> "$GITHUB_ENV"
|
||||
|
||||
- name: Prepare LLVM cache path (Unix)
|
||||
if: runner.os != 'Windows'
|
||||
shell: bash
|
||||
run: |
|
||||
set -eux
|
||||
sudo mkdir -p /opt/llvm
|
||||
sudo chown -R "$(whoami)" /opt/llvm
|
||||
|
||||
# ---- Cache LLVM prefix ----
|
||||
- name: Cache LLVM
|
||||
uses: actions/cache@v5.0.5
|
||||
id: llvm-cache
|
||||
with:
|
||||
path: ${{ runner.os == 'Windows' && 'C:/opt/llvm' || '/opt/llvm' }}
|
||||
key: tvm-wheel-llvm-${{ env.LLVM_VERSION }}-${{ runner.os }}-${{ inputs.arch }}-v6
|
||||
|
||||
# ---- Install LLVM via conda (cache miss only) ----
|
||||
- name: Setup conda
|
||||
if: steps.llvm-cache.outputs.cache-hit != 'true'
|
||||
uses: conda-incubator/setup-miniconda@v4.0.1
|
||||
continue-on-error: true
|
||||
id: conda1
|
||||
with:
|
||||
miniforge-version: latest
|
||||
conda-remove-defaults: true
|
||||
|
||||
- name: Setup conda (retry with tar.bz2)
|
||||
if: steps.llvm-cache.outputs.cache-hit != 'true' && steps.conda1.outcome == 'failure'
|
||||
uses: conda-incubator/setup-miniconda@v4.0.1
|
||||
with:
|
||||
miniforge-version: latest
|
||||
use-only-tar-bz2: true
|
||||
conda-remove-defaults: true
|
||||
|
||||
- name: Install LLVM (Unix)
|
||||
if: steps.llvm-cache.outputs.cache-hit != 'true' && runner.os != 'Windows'
|
||||
shell: bash -l {0}
|
||||
run: |
|
||||
set -eux
|
||||
if [[ "${RUNNER_OS}" == "Linux" ]]; then
|
||||
sudo mkdir -p /opt/llvm
|
||||
sudo chown -R "$(whoami)" /opt/llvm
|
||||
fi
|
||||
conda create -q -p /opt/llvm -c conda-forge \
|
||||
"llvmdev=${LLVM_VERSION}" "clangdev=${LLVM_VERSION}" "compiler-rt=${LLVM_VERSION}" zlib zstd-static libxml2-devel \
|
||||
-y
|
||||
|
||||
- name: Install LLVM (Windows)
|
||||
if: steps.llvm-cache.outputs.cache-hit != 'true' && runner.os == 'Windows'
|
||||
shell: cmd /C call {0}
|
||||
run: |
|
||||
call conda create -q -p C:\opt\llvm -c conda-forge llvmdev=%LLVM_VERSION% zlib zstd-static libxml2-devel -y
|
||||
|
||||
# The {project} placeholder is not expanded inside CIBW_ENVIRONMENT values, so
|
||||
# compute the forward-slash host path here (the Windows analog of the Linux
|
||||
# /project hardcode).
|
||||
- name: Compute CUDA sidecar path (Windows)
|
||||
if: runner.os == 'Windows' && inputs.include_cuda_runtime == '1'
|
||||
shell: bash
|
||||
run: echo "TVM_CUDA_EXTRA_LIB=$(cygpath -m "$(pwd)")/build-wheel-cuda/lib/tvm_runtime_cuda.dll" >> "$GITHUB_ENV"
|
||||
|
||||
# ---- Build and test wheels ----
|
||||
- name: Build and test wheels
|
||||
uses: pypa/cibuildwheel@294735312765b09d24a2fbec22660ce817587d55 # v4.1.0
|
||||
with:
|
||||
package-dir: .
|
||||
output-dir: wheelhouse
|
||||
env:
|
||||
CIBW_BUILD: ${{ inputs.build }}
|
||||
CIBW_ARCHS_LINUX: ${{ inputs.arch }}
|
||||
CIBW_ARCHS_MACOS: ${{ inputs.arch }}
|
||||
CIBW_ARCHS_WINDOWS: ${{ inputs.arch }}
|
||||
# Linux builds run in cibuildwheel's default manylinux_2_28 container;
|
||||
# bind-mount the cached LLVM prefix into it. Ignored on macOS/Windows,
|
||||
# which build without a container.
|
||||
CIBW_CONTAINER_ENGINE: "docker; create_args: --volume /opt/llvm:/opt/llvm:ro"
|
||||
# Each per-OS block carries the toolchain location (conda LLVM prefix +
|
||||
# llvm-config path), the universal static-link policy (USE_LLVM --link-static
|
||||
# and ZLIB_USE_STATIC_LIBS), and the CUDA sidecar. Feature defines that vary by
|
||||
# wheel (e.g. USE_METAL on macOS) come from the matrix via inputs.cmake_defines.
|
||||
# One explicit block per build platform (macOS / Linux / Windows); cibuildwheel
|
||||
# env overrides replace rather than merge, so there is no shared base block.
|
||||
CIBW_ENVIRONMENT_MACOS: >-
|
||||
CMAKE_PREFIX_PATH="/opt/llvm"
|
||||
CMAKE_ARGS="-DUSE_LLVM='/opt/llvm/bin/llvm-config --link-static' -DZLIB_USE_STATIC_LIBS=ON -DCMAKE_PREFIX_PATH=/opt/llvm ${{ inputs.cmake_defines }}"
|
||||
CIBW_ENVIRONMENT_LINUX: >-
|
||||
CMAKE_PREFIX_PATH="/opt/llvm"
|
||||
LIBRARY_PATH="/opt/llvm/lib"
|
||||
CMAKE_ARGS="-DUSE_LLVM='/opt/llvm/bin/llvm-config --link-static' -DZLIB_USE_STATIC_LIBS=ON -DCMAKE_PREFIX_PATH=/opt/llvm ${{ inputs.cmake_defines }} -DTVM_PACKAGE_EXTRA_LIBS=/project/build-wheel-cuda/lib/libtvm_runtime_cuda.so"
|
||||
CIBW_ENVIRONMENT_WINDOWS: >-
|
||||
CMAKE_PREFIX_PATH="C:/opt/llvm/Library"
|
||||
PATH="C:/opt/llvm/Library/bin;$PATH"
|
||||
CMAKE_ARGS="-DUSE_LLVM='C:/opt/llvm/Library/bin/llvm-config.exe --link-static' -DZLIB_USE_STATIC_LIBS=ON -DCMAKE_PREFIX_PATH=C:/opt/llvm/Library ${{ inputs.cmake_defines }} -DTVM_PACKAGE_EXTRA_LIBS=${{ env.TVM_CUDA_EXTRA_LIB }}"
|
||||
# Turns the wheel-specific assertions in
|
||||
# tests/python/all-platform-minimal-test/test_validate_runtime_library.py
|
||||
# ON (they skip unless these are set). Every published wheel is LLVM-enabled,
|
||||
# so TVM_WHEEL_EXPECT_LLVM is always "1"; the CUDA runtime is only bundled on
|
||||
# the CUDA wheels, so TVM_WHEEL_EXPECT_CUDA_RUNTIME is "0" for CPU wheels.
|
||||
CIBW_TEST_ENVIRONMENT: >-
|
||||
TVM_WHEEL_EXPECT_LLVM="1"
|
||||
TVM_WHEEL_EXPECT_CUDA_RUNTIME="${{ inputs.include_cuda_runtime }}"
|
||||
@@ -0,0 +1,40 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
name: Detect Environment Variables
|
||||
description: Detects environment variables such as CPU count and sets them as outputs.
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: Run Python to detect environment variables
|
||||
shell: python
|
||||
id: detect
|
||||
run: |
|
||||
import multiprocessing, os
|
||||
|
||||
output_file = open(os.environ.get("GITHUB_OUTPUT"), "a")
|
||||
|
||||
def write_env_var(name, value):
|
||||
output_file.write(f"{name}={value}\n")
|
||||
print(f"Detected environment variable: {name}={value}")
|
||||
|
||||
write_env_var("cpu_count", multiprocessing.cpu_count())
|
||||
|
||||
outputs:
|
||||
cpu_count:
|
||||
description: "The number of CPU cores"
|
||||
value: ${{ steps.detect.outputs.cpu_count }}
|
||||
@@ -0,0 +1,47 @@
|
||||
name: Setup TVM CI environment
|
||||
description: Set up the cached conda build environment and install tvm-ffi.
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- uses: actions/cache@v5.0.5
|
||||
env:
|
||||
CACHE_NUMBER: 2
|
||||
with:
|
||||
path: ~/conda_pkgs_dir
|
||||
key: ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}-${{ hashFiles('ci/scripts/package/build-environment.yaml') }}
|
||||
- uses: conda-incubator/setup-miniconda@v4.0.1
|
||||
continue-on-error: true
|
||||
id: conda1
|
||||
with:
|
||||
activate-environment: tvm-build
|
||||
channel-priority: strict
|
||||
environment-file: ci/scripts/package/build-environment.yaml
|
||||
auto-activate-base: false
|
||||
miniforge-version: latest
|
||||
python-version: "3.10"
|
||||
condarc-file: tests/conda/condarc
|
||||
conda-remove-defaults: true
|
||||
- uses: conda-incubator/setup-miniconda@v4.0.1
|
||||
if: steps.conda1.outcome == 'failure'
|
||||
with:
|
||||
activate-environment: tvm-build
|
||||
channel-priority: strict
|
||||
environment-file: ci/scripts/package/build-environment.yaml
|
||||
auto-activate-base: false
|
||||
miniforge-version: latest
|
||||
use-only-tar-bz2: true
|
||||
python-version: "3.10"
|
||||
condarc-file: tests/conda/condarc
|
||||
conda-remove-defaults: true
|
||||
- name: Conda info
|
||||
shell: pwsh
|
||||
run: |
|
||||
mamba info
|
||||
mamba list
|
||||
mamba info --envs
|
||||
mamba list --name base
|
||||
- name: Install tvm-ffi pip package
|
||||
shell: bash -l {0}
|
||||
run: |
|
||||
pip install -v ./3rdparty/tvm-ffi
|
||||
@@ -0,0 +1,15 @@
|
||||
# See https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file#about-the-dependabotyml-file
|
||||
version: 2
|
||||
|
||||
updates:
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "monthly"
|
||||
open-pull-requests-limit: 0
|
||||
|
||||
- package-ecosystem: "pip"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "monthly"
|
||||
open-pull-requests-limit: 0
|
||||
@@ -0,0 +1,41 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
name: Lint
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
pull_request:
|
||||
branches: [main]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: Lint-${{ github.event.pull_request.number || github.sha }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v6.0.2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
fetch-tags: true
|
||||
- uses: pre-commit/action@2c7b3805fd2a0fd8c1884dcaebf91fc102a13ecd # v3.0.1
|
||||
@@ -0,0 +1,119 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
# GH actions.
|
||||
# We use it to cover windows and mac builds
|
||||
# Jenkins is still the primary CI
|
||||
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: CI-${{ github.event.pull_request.number || github.sha }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
MacOS:
|
||||
if: ${{ github.repository == 'apache/tvm' }}
|
||||
runs-on: macOS-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v6.0.2
|
||||
with:
|
||||
submodules: 'recursive'
|
||||
- name: Set up environment
|
||||
uses: ./.github/actions/setup
|
||||
- name: Detect environment variables
|
||||
uses: ./.github/actions/detect-env-vars
|
||||
id: env_vars
|
||||
- name: Build TVM wheel
|
||||
shell: bash -l {0}
|
||||
env:
|
||||
CMAKE_BUILD_PARALLEL_LEVEL: ${{ steps.env_vars.outputs.cpu_count }}
|
||||
run: |
|
||||
pip install scikit-build-core
|
||||
export CMAKE_ARGS="-DUSE_LLVM=ON -DBUILD_TESTING=OFF"
|
||||
pip wheel --no-deps -w dist . -v
|
||||
- name: Install TVM from wheel
|
||||
shell: bash -l {0}
|
||||
run: |
|
||||
export TVM_FFI_VERSION="$(python -c 'from importlib.metadata import version; print(version("apache-tvm-ffi"))')"
|
||||
pip install ml_dtypes
|
||||
# Keep the source-matched tvm-ffi installed by the setup action.
|
||||
pip install --no-deps dist/*.whl
|
||||
python - <<'PY'
|
||||
import os
|
||||
from importlib.metadata import requires, version
|
||||
|
||||
assert version("apache-tvm-ffi") == os.environ["TVM_FFI_VERSION"]
|
||||
assert "apache-tvm-ffi>=0.1.13" in requires("apache-tvm")
|
||||
PY
|
||||
|
||||
- name: Test
|
||||
shell: bash -l {0}
|
||||
run: >-
|
||||
python -m pytest -v tests/python/all-platform-minimal-test
|
||||
- name: Minimal Metal Compile-Only
|
||||
shell: bash -l {0}
|
||||
run: |
|
||||
python -m pytest -v -s 'tests/python/codegen/test_gpu_codegen_allreduce.py::test_allreduce_sum_compile'
|
||||
python -m pytest -v -s 'tests/python/codegen/test_target_codegen_metal.py::test_func_with_trailing_pod_params'
|
||||
- name: Minimal Metal Compile-and-Run
|
||||
shell: bash -l {0}
|
||||
run: |
|
||||
python -m pytest -v -s 'tests/python/codegen/test_target_codegen_metal.py'
|
||||
python -m pytest -v -s 'tests/python/codegen/test_target_codegen_gpu_common.py'
|
||||
python -m pytest -v -s 'tests/python/codegen/test_gpu_codegen_allreduce.py::test_allreduce_sum[dims0-metal]'
|
||||
|
||||
Windows:
|
||||
if: ${{ github.repository == 'apache/tvm' }}
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v6.0.2
|
||||
with:
|
||||
submodules: 'recursive'
|
||||
- name: Set up environment
|
||||
uses: ./.github/actions/setup
|
||||
- name: Detect environment variables
|
||||
uses: ./.github/actions/detect-env-vars
|
||||
id: env_vars
|
||||
- name: Install TVM
|
||||
shell: cmd /C call {0}
|
||||
env:
|
||||
CMAKE_BUILD_PARALLEL_LEVEL: ${{ steps.env_vars.outputs.cpu_count }}
|
||||
run: |
|
||||
pip install scikit-build-core
|
||||
set CMAKE_ARGS=-DUSE_LLVM=ON -DBUILD_TESTING=OFF
|
||||
pip install --no-deps . -v
|
||||
- name: Install test dependencies
|
||||
shell: cmd /C call {0}
|
||||
run: |
|
||||
pip install psutil cloudpickle ml_dtypes numpy packaging scipy tornado typing_extensions
|
||||
- name: Test
|
||||
shell: cmd /C call {0}
|
||||
run: >-
|
||||
python -m pytest -v tests/python/all-platform-minimal-test
|
||||
@@ -0,0 +1,24 @@
|
||||
|
||||
name: Nightly Docker Update
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
group: nightly-docker-update
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
open_update_pr:
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
if: github.repository == 'apache/tvm'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v6.0.2
|
||||
- name: Open PR to update Docker images
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
set -eux
|
||||
python ci/scripts/jenkins/open_docker_update_pr.py
|
||||
@@ -0,0 +1,219 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
name: Publish TVM wheels
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
tag:
|
||||
description: "Tag, branch, or SHA to build"
|
||||
required: true
|
||||
type: string
|
||||
publish_repository:
|
||||
description: "Where to publish after the wheel build succeeds"
|
||||
required: true
|
||||
default: "none"
|
||||
type: choice
|
||||
options:
|
||||
- none
|
||||
- pypi
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
# CI runners are ephemeral, so pip's HTTP cache buys nothing and a stale
|
||||
# preinstalled cache (e.g. on the macOS image) only produces noisy
|
||||
# "Cache entry deserialization failed" warnings. Disable it everywhere.
|
||||
env:
|
||||
PIP_NO_CACHE_DIR: "1"
|
||||
|
||||
jobs:
|
||||
# Build the CUDA runtime sidecar once per arch and upload it as an artifact that
|
||||
# build_wheels bundles. The Linux legs build inside the official manylinux_2_28
|
||||
# CUDA image (CUDA toolkit preinstalled, see pypa/manylinux) -- the same glibc
|
||||
# baseline cibuildwheel targets for the wheel -- so the sidecar stays
|
||||
# ABI-compatible with the wheel's libtvm_runtime.so regardless of the exact tag.
|
||||
build_cuda_runtime:
|
||||
name: ${{ matrix.name }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
container: ${{ matrix.container }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- name: "CUDA runtime sidecar (Linux x86_64, manylinux_2_28)"
|
||||
os: ubuntu-latest
|
||||
container: quay.io/manylinux_cuda/manylinux_2_28_x86_64_cuda13_1:latest
|
||||
arch: x86_64
|
||||
script: ci/scripts/package/manylinux_build_libtvm_runtime_cuda.sh
|
||||
lib: build-wheel-cuda/lib/libtvm_runtime_cuda.so
|
||||
- name: "CUDA runtime sidecar (Linux aarch64, manylinux_2_28)"
|
||||
os: ubuntu-24.04-arm
|
||||
container: quay.io/manylinux_cuda/manylinux_2_28_aarch64_cuda13_1:latest
|
||||
arch: aarch64
|
||||
script: ci/scripts/package/manylinux_build_libtvm_runtime_cuda.sh
|
||||
lib: build-wheel-cuda/lib/libtvm_runtime_cuda.so
|
||||
- name: "CUDA runtime sidecar (Windows AMD64)"
|
||||
os: windows-2022
|
||||
container: ""
|
||||
arch: AMD64
|
||||
script: ci/scripts/package/windows_build_libtvm_runtime_cuda.bat
|
||||
lib: build-wheel-cuda/lib/tvm_runtime_cuda.dll
|
||||
steps:
|
||||
# The containerized Linux legs check out as root; mark the tree safe so git
|
||||
# (submodule init in checkout) does not bail on "dubious ownership".
|
||||
- name: Mark workspace safe for git
|
||||
if: runner.os == 'Linux'
|
||||
shell: bash
|
||||
run: git config --global --add safe.directory '*'
|
||||
|
||||
- name: Checkout source
|
||||
uses: actions/checkout@v6.0.2
|
||||
with:
|
||||
ref: ${{ inputs.tag }}
|
||||
submodules: recursive
|
||||
fetch-depth: 1
|
||||
fetch-tags: true
|
||||
|
||||
# Windows has no manylinux interpreter; the script's pip install needs one.
|
||||
- name: Set up Python (Windows host)
|
||||
if: runner.os == 'Windows'
|
||||
uses: actions/setup-python@v6.2.0
|
||||
with:
|
||||
python-version: "3.10"
|
||||
|
||||
- name: Build CUDA runtime sidecar (Unix)
|
||||
if: runner.os != 'Windows'
|
||||
shell: bash
|
||||
run: bash ${{ matrix.script }}
|
||||
|
||||
- name: Build CUDA runtime sidecar (Windows)
|
||||
if: runner.os == 'Windows'
|
||||
shell: cmd
|
||||
run: call ${{ matrix.script }}
|
||||
|
||||
- name: Upload CUDA runtime sidecar
|
||||
uses: actions/upload-artifact@v7.0.1
|
||||
with:
|
||||
name: tvm-cuda-runtime-${{ matrix.arch }}
|
||||
path: ${{ matrix.lib }}
|
||||
if-no-files-found: error
|
||||
|
||||
build_wheels:
|
||||
name: ${{ matrix.name }}
|
||||
# All-or-nothing: a failed sidecar leg blocks the whole wheel matrix (a publish
|
||||
# needs the complete 4-wheel set anyway).
|
||||
needs: [build_cuda_runtime]
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- name: "Linux x86_64 wheel with CUDA runtime (manylinux_2_28)"
|
||||
os: ubuntu-latest
|
||||
arch: x86_64
|
||||
build: cp310-manylinux_x86_64
|
||||
include_cuda_runtime: "1"
|
||||
artifact_suffix: linux-x86_64-manylinux_2_28
|
||||
- name: "Linux aarch64 wheel with CUDA runtime (manylinux_2_28)"
|
||||
os: ubuntu-24.04-arm
|
||||
arch: aarch64
|
||||
build: cp310-manylinux_aarch64
|
||||
include_cuda_runtime: "1"
|
||||
artifact_suffix: linux-aarch64-manylinux_2_28
|
||||
- name: "macOS arm64 wheel with Metal"
|
||||
os: macos-14
|
||||
arch: arm64
|
||||
build: cp310-macosx_arm64
|
||||
include_cuda_runtime: "0"
|
||||
artifact_suffix: macos-arm64
|
||||
cmake_defines: "-DUSE_METAL=ON"
|
||||
- name: "Windows AMD64 wheel with CUDA runtime"
|
||||
os: windows-2022
|
||||
arch: AMD64
|
||||
build: cp310-win_amd64
|
||||
include_cuda_runtime: "1"
|
||||
artifact_suffix: windows-amd64
|
||||
steps:
|
||||
- name: Checkout source
|
||||
uses: actions/checkout@v6.0.2
|
||||
with:
|
||||
ref: ${{ inputs.tag }}
|
||||
submodules: recursive
|
||||
# Full history + tags so setuptools_scm can derive the wheel version from
|
||||
# the most recent Git tag during the build (shallow clones break it).
|
||||
fetch-depth: 0
|
||||
fetch-tags: true
|
||||
|
||||
# Land the sidecar where -DTVM_PACKAGE_EXTRA_LIBS / cibuildwheel's /project
|
||||
# mount expects it. Skipped on CPU-only rows (macOS).
|
||||
- name: Download CUDA runtime sidecar
|
||||
if: ${{ matrix.include_cuda_runtime == '1' }}
|
||||
uses: actions/download-artifact@v8.0.1
|
||||
with:
|
||||
name: tvm-cuda-runtime-${{ matrix.arch }}
|
||||
path: build-wheel-cuda/lib
|
||||
|
||||
- name: Build TVM wheel
|
||||
uses: ./.github/actions/build-wheel-for-publish
|
||||
with:
|
||||
arch: ${{ matrix.arch }}
|
||||
build: ${{ matrix.build }}
|
||||
cmake_defines: ${{ matrix.cmake_defines }}
|
||||
include_cuda_runtime: ${{ matrix.include_cuda_runtime }}
|
||||
|
||||
- name: Upload wheel artifact
|
||||
uses: actions/upload-artifact@v7.0.1
|
||||
with:
|
||||
name: tvm-wheel-${{ matrix.artifact_suffix }}
|
||||
path: wheelhouse/*.whl
|
||||
if-no-files-found: error
|
||||
|
||||
upload_pypi:
|
||||
name: Upload package distributions
|
||||
needs: [build_wheels]
|
||||
if: ${{ inputs.publish_repository != 'none' }}
|
||||
runs-on: ubuntu-latest
|
||||
environment: ${{ inputs.publish_repository }}
|
||||
permissions:
|
||||
id-token: write
|
||||
attestations: write
|
||||
steps:
|
||||
- uses: actions/download-artifact@v8.0.1
|
||||
with:
|
||||
pattern: tvm-wheel-*
|
||||
path: dist
|
||||
merge-multiple: true
|
||||
|
||||
# Print wheel sizes for visibility only. We do not fail on the PyPI 100 MB
|
||||
# limit here -- the publish step's upload would surface that error directly.
|
||||
- name: Print wheel sizes
|
||||
shell: bash
|
||||
run: ls -alh dist/*.whl
|
||||
|
||||
- name: Generate artifact attestation for wheels
|
||||
uses: actions/attest-build-provenance@v4.1.0
|
||||
with:
|
||||
subject-path: dist/*
|
||||
|
||||
- name: Publish package distributions to PyPI
|
||||
if: ${{ inputs.publish_repository == 'pypi' }}
|
||||
uses: pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e # v1.13.0
|
||||
with:
|
||||
attestations: true
|
||||
verbose: true
|
||||
@@ -0,0 +1,31 @@
|
||||
|
||||
name: tvm-bot
|
||||
on:
|
||||
issue_comment:
|
||||
types: [created]
|
||||
|
||||
concurrency:
|
||||
group: merge-${{ github.event.issue.number }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
run-tvm-bot:
|
||||
permissions:
|
||||
contents: write
|
||||
issues: write
|
||||
pull-requests: write
|
||||
if: ${{ github.event.issue.pull_request && startsWith(github.event.comment.body, '@tvm-bot ') && github.repository == 'apache/tvm' }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v6.0.2
|
||||
- name: Run tvm-bot
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
GH_ACTIONS_TOKEN: ${{ secrets.GH_ACTIONS_TOKEN }}
|
||||
TVM_BOT_JENKINS_TOKEN: ${{ secrets.TVM_BOT_JENKINS_TOKEN }}
|
||||
PR_NUMBER: ${{ github.event.issue.number }}
|
||||
ISSUE_COMMENT: ${{ toJson(github.event.comment) }}
|
||||
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
|
||||
run: |
|
||||
set -eux
|
||||
python ci/scripts/github/github_tvmbot.py --pr "$PR_NUMBER" --run-url "$RUN_URL" --trigger-comment-json "$ISSUE_COMMENT"
|
||||
+296
@@ -0,0 +1,296 @@
|
||||
|
||||
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
*.S
|
||||
# C extensions
|
||||
*.so
|
||||
*.ll
|
||||
.npm
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
env/
|
||||
build/
|
||||
build-*/
|
||||
!.github/actions/build-*/
|
||||
!.github/actions/build-*/action.yml
|
||||
develop-eggs/
|
||||
dist/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
.conda/
|
||||
# PyInstaller
|
||||
# Usually these files are written by a python script from a template
|
||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||
*.manifest
|
||||
*.spec
|
||||
|
||||
# Generated by python/gen_requirements.py
|
||||
python/requirements/*.txt
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
htmlcov/
|
||||
.tox/
|
||||
.coverage
|
||||
.coverage.*
|
||||
.cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
*,cover
|
||||
.hypothesis/
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
*.pot
|
||||
|
||||
# Django stuff:
|
||||
*.log
|
||||
local_settings.py
|
||||
|
||||
# Flask stuff:
|
||||
instance/
|
||||
.webassets-cache
|
||||
|
||||
# Scrapy stuff:
|
||||
.scrapy
|
||||
|
||||
# Sphinx documentation
|
||||
docs/_build/
|
||||
docs/_staging/
|
||||
|
||||
# PyBuilder
|
||||
/target/
|
||||
|
||||
# IPython Notebook
|
||||
.ipynb_checkpoints
|
||||
|
||||
# pyenv
|
||||
.python-version
|
||||
|
||||
# celery beat schedule file
|
||||
celerybeat-schedule
|
||||
|
||||
# dotenv
|
||||
.env
|
||||
|
||||
# virtualenv
|
||||
venv/
|
||||
ENV/
|
||||
|
||||
# Spyder project settings
|
||||
.spyderproject
|
||||
|
||||
# Rope project settings
|
||||
.ropeproject
|
||||
*~
|
||||
*.pyc
|
||||
*~
|
||||
config.mk
|
||||
config.cmake
|
||||
Win32
|
||||
*.dir
|
||||
perf
|
||||
*.wasm
|
||||
.emscripten
|
||||
|
||||
## IOS
|
||||
DerivedData/
|
||||
|
||||
## Java
|
||||
*.class
|
||||
jvm/*/target/
|
||||
jvm/*/*/target/
|
||||
jvm/native/*/generated
|
||||
jvm/native/src/main/native/org_apache_tvm_native_c_api.h
|
||||
*.worksheet
|
||||
*.idea
|
||||
*.iml
|
||||
*.classpath
|
||||
*.project
|
||||
*.settings
|
||||
*/node_modules/
|
||||
|
||||
## Various settings
|
||||
*.pbxuser
|
||||
!default.pbxuser
|
||||
*.mode1v3
|
||||
!default.mode1v3
|
||||
*.mode2v3
|
||||
!default.mode2v3
|
||||
*.perspectivev3
|
||||
!default.perspectivev3
|
||||
xcuserdata/
|
||||
.pkl_memoize_*
|
||||
|
||||
.emscripten*
|
||||
.m2
|
||||
|
||||
# Compiled Dynamic libraries
|
||||
*.so
|
||||
*.dylib
|
||||
*.dll
|
||||
|
||||
# Compiled Object files
|
||||
*.slo
|
||||
*.lo
|
||||
*.o
|
||||
*.obj
|
||||
|
||||
# Precompiled Headers
|
||||
*.gch
|
||||
*.pch
|
||||
|
||||
# Compiled Static libraries
|
||||
*.lai
|
||||
*.la
|
||||
*.a
|
||||
*.lib
|
||||
|
||||
# Executables
|
||||
*.exe
|
||||
*.out
|
||||
*.app
|
||||
|
||||
## Other
|
||||
*.moved-aside
|
||||
*.xccheckout
|
||||
*.xcscmblueprint
|
||||
.DS_Store
|
||||
tags
|
||||
cscope*
|
||||
*.lock
|
||||
|
||||
# vim temporary files
|
||||
*.swp
|
||||
*.swo
|
||||
|
||||
# TVM generated code
|
||||
perf
|
||||
.bash_history
|
||||
*.json
|
||||
*.params
|
||||
*.ro
|
||||
*.onnx
|
||||
*.h5
|
||||
synset.txt
|
||||
cat.jpg
|
||||
cat.png
|
||||
docs.tgz
|
||||
cat.png
|
||||
*.mlmodel
|
||||
tvm_u.*
|
||||
tvm_t.*
|
||||
# Mac OS X
|
||||
.DS_Store
|
||||
|
||||
# Jetbrain
|
||||
.idea
|
||||
.ipython
|
||||
.jupyter
|
||||
.nv
|
||||
.pylint.d
|
||||
.python_history
|
||||
.pytest_cache
|
||||
.local
|
||||
cmake-build-debug
|
||||
|
||||
# Visual Studio
|
||||
.vs
|
||||
|
||||
# Visual Studio Code
|
||||
.vscode
|
||||
|
||||
# tmp file
|
||||
.nfs*
|
||||
|
||||
# keys
|
||||
*.pem
|
||||
*.p12
|
||||
*.pfx
|
||||
*.cer
|
||||
*.crt
|
||||
*.der
|
||||
|
||||
# patch sentinel
|
||||
patched.txt
|
||||
|
||||
# Python type checking
|
||||
.mypy_cache/
|
||||
.pyre/
|
||||
|
||||
# pipenv files
|
||||
Pipfile
|
||||
Pipfile.lock
|
||||
|
||||
# conda package artifacts
|
||||
conda/Dockerfile.cuda*
|
||||
conda/pkg
|
||||
.node_repl_history
|
||||
# nix files
|
||||
.envrc
|
||||
*.nix
|
||||
|
||||
# Docker files
|
||||
.sudo_as_admin_successful
|
||||
|
||||
# Downloaded models/datasets
|
||||
.tvm_test_data
|
||||
.dgl
|
||||
.caffe2
|
||||
|
||||
# Local docs build
|
||||
_docs/
|
||||
jvm/target
|
||||
.config/configstore/
|
||||
.ci-py-scripts/
|
||||
|
||||
# Generated Hexagon files
|
||||
src/runtime/hexagon/rpc/hexagon_rpc.h
|
||||
src/runtime/hexagon/rpc/hexagon_rpc_skel.c
|
||||
src/runtime/hexagon/rpc/hexagon_rpc_stub.c
|
||||
|
||||
# Local tvm-site checkout
|
||||
tvm-site/
|
||||
|
||||
# Test sample data files
|
||||
!tests/python/ci/sample_prs/*.json
|
||||
|
||||
# Used in CI to communicate between Python and Jenkins
|
||||
.docker-image-names/
|
||||
|
||||
# Printed TIR code on disk
|
||||
*.tir
|
||||
|
||||
# GDB history file
|
||||
.gdb_history
|
||||
|
||||
# Less command history file
|
||||
.lesshst
|
||||
|
||||
# Agent tracking files
|
||||
LOG.md
|
||||
STATUS.md
|
||||
|
||||
# Local editable-install artifacts (pip install -e .)
|
||||
python/tvm_ffi/
|
||||
# Generated by setuptools_scm at build time
|
||||
python/tvm/_version.py
|
||||
python/bin/
|
||||
python/typing_extensions.py
|
||||
python/*.dist-info/
|
||||
pytest-of-bohanhou/
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
[submodule "3rdparty/cutlass"]
|
||||
path = 3rdparty/cutlass
|
||||
url = https://github.com/NVIDIA/cutlass.git
|
||||
[submodule "3rdparty/OpenCL-Headers"]
|
||||
path = 3rdparty/OpenCL-Headers
|
||||
url = https://github.com/KhronosGroup/OpenCL-Headers.git
|
||||
[submodule "3rdparty/cutlass_fpA_intB_gemm"]
|
||||
path = 3rdparty/cutlass_fpA_intB_gemm
|
||||
url = https://github.com/tlc-pack/cutlass_fpA_intB_gemm
|
||||
[submodule "3rdparty/libflash_attn"]
|
||||
path = 3rdparty/libflash_attn
|
||||
url = https://github.com/tlc-pack/libflash_attn
|
||||
[submodule "3rdparty/tvm-ffi"]
|
||||
path = 3rdparty/tvm-ffi
|
||||
url = https://github.com/apache/tvm-ffi
|
||||
@@ -0,0 +1,19 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
config:
|
||||
MD013: false
|
||||
@@ -0,0 +1,99 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
exclude: ^(\.txdev/|\.claude/)
|
||||
|
||||
default_install_hook_types:
|
||||
- pre-commit
|
||||
repos:
|
||||
# ---------- Local hooks ----------
|
||||
- repo: local
|
||||
hooks:
|
||||
- id: check-asf-header
|
||||
name: check ASF Header
|
||||
entry: python tests/lint/check_asf_header.py --check
|
||||
language: python
|
||||
language_version: python3
|
||||
pass_filenames: false
|
||||
verbose: false
|
||||
- id: check-file-type
|
||||
name: check file types
|
||||
entry: python tests/lint/check_file_type.py
|
||||
language: python
|
||||
language_version: python3
|
||||
pass_filenames: false
|
||||
verbose: false
|
||||
# ---------- General file checks ----------
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v5.0.0
|
||||
hooks:
|
||||
- id: check-added-large-files
|
||||
- id: check-case-conflict
|
||||
- id: check-merge-conflict
|
||||
- id: check-symlinks
|
||||
- id: end-of-file-fixer
|
||||
exclude: ^3rdparty/
|
||||
- id: mixed-line-ending
|
||||
exclude: ^3rdparty/
|
||||
- id: requirements-txt-fixer
|
||||
exclude: ^docker/python/bootstrap
|
||||
- id: trailing-whitespace
|
||||
exclude: ^3rdparty/
|
||||
- id: check-yaml
|
||||
- id: check-toml
|
||||
|
||||
# ---------- YAML lint ----------
|
||||
- repo: https://github.com/adrienverge/yamllint
|
||||
rev: v1.35.1
|
||||
hooks:
|
||||
- id: yamllint
|
||||
args:
|
||||
- --config-file
|
||||
- .yamllint.yaml
|
||||
exclude: ^\.github/
|
||||
|
||||
# ---------- TOML format ----------
|
||||
- repo: https://github.com/ComPWA/taplo-pre-commit
|
||||
rev: v0.9.3
|
||||
hooks:
|
||||
- id: taplo-format
|
||||
|
||||
# ---------- Python: ruff ----------
|
||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||
rev: v0.12.3
|
||||
hooks:
|
||||
- id: ruff-check
|
||||
types_or: [python, pyi, jupyter]
|
||||
args: [--fix]
|
||||
- id: ruff-format
|
||||
types_or: [python, pyi, jupyter]
|
||||
|
||||
# ---------- C/C++: clang-format ----------
|
||||
- repo: https://github.com/pre-commit/mirrors-clang-format
|
||||
rev: "v20.1.8"
|
||||
hooks:
|
||||
- id: clang-format
|
||||
types_or: [c, c++, cuda, objective-c++]
|
||||
exclude: ^3rdparty/
|
||||
|
||||
# ---------- Cython ----------
|
||||
- repo: https://github.com/MarcoGorelli/cython-lint
|
||||
rev: v0.16.7
|
||||
hooks:
|
||||
- id: cython-lint
|
||||
args: [--max-line-length=120]
|
||||
- id: double-quote-cython-strings
|
||||
@@ -0,0 +1,32 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
extends: default
|
||||
|
||||
rules:
|
||||
document-start: disable
|
||||
line-length:
|
||||
max: 120
|
||||
level: warning
|
||||
truthy:
|
||||
allowed-values:
|
||||
- "on"
|
||||
- "off"
|
||||
- "yes"
|
||||
- "no"
|
||||
- "true"
|
||||
- "false"
|
||||
Vendored
+246
@@ -0,0 +1,246 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2015 by llvm/compiler-rt contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
* \file builtin_fp16.h
|
||||
* \brief Functions for conversion between fp32 and fp16, adopted from compiler-rt.
|
||||
*/
|
||||
#ifndef COMPILER_RT_BUILTIN_FP16_H_
|
||||
#define COMPILER_RT_BUILTIN_FP16_H_
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable : 4305 4805)
|
||||
#endif
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
static inline uint32_t __clz(uint32_t x) {
|
||||
// count leading zeros
|
||||
int n = 32;
|
||||
uint32_t y;
|
||||
|
||||
y = x >> 16;
|
||||
if (y) {
|
||||
n = n - 16;
|
||||
x = y;
|
||||
}
|
||||
y = x >> 8;
|
||||
if (y) {
|
||||
n = n - 8;
|
||||
x = y;
|
||||
}
|
||||
y = x >> 4;
|
||||
if (y) {
|
||||
n = n - 4;
|
||||
x = y;
|
||||
}
|
||||
y = x >> 2;
|
||||
if (y) {
|
||||
n = n - 2;
|
||||
x = y;
|
||||
}
|
||||
y = x >> 1;
|
||||
if (y) return n - 2;
|
||||
return n - x;
|
||||
}
|
||||
|
||||
template <typename SRC_T, typename SRC_REP_T, int SRC_SIG_BITS, typename DST_T, typename DST_REP_T,
|
||||
int DST_SIG_BITS>
|
||||
static inline DST_T __truncXfYf2__(SRC_T a) {
|
||||
// Various constants whose values follow from the type parameters.
|
||||
// Any reasonable optimizer will fold and propagate all of these.
|
||||
const int srcBits = sizeof(SRC_T) * 8;
|
||||
const int srcExpBits = srcBits - SRC_SIG_BITS - 1;
|
||||
const int srcInfExp = (1 << srcExpBits) - 1;
|
||||
const int srcExpBias = srcInfExp >> 1;
|
||||
|
||||
const SRC_REP_T srcMinNormal = SRC_REP_T(1) << SRC_SIG_BITS;
|
||||
const SRC_REP_T srcSignificandMask = srcMinNormal - 1;
|
||||
const SRC_REP_T srcInfinity = (SRC_REP_T)srcInfExp << SRC_SIG_BITS;
|
||||
const SRC_REP_T srcSignMask = SRC_REP_T(1) << (SRC_SIG_BITS + srcExpBits);
|
||||
const SRC_REP_T srcAbsMask = srcSignMask - 1;
|
||||
const SRC_REP_T roundMask = (SRC_REP_T(1) << (SRC_SIG_BITS - DST_SIG_BITS)) - 1;
|
||||
const SRC_REP_T halfway = SRC_REP_T(1) << (SRC_SIG_BITS - DST_SIG_BITS - 1);
|
||||
const SRC_REP_T srcQNaN = SRC_REP_T(1) << (SRC_SIG_BITS - 1);
|
||||
const SRC_REP_T srcNaNCode = srcQNaN - 1;
|
||||
|
||||
const int dstBits = sizeof(DST_T) * 8;
|
||||
const int dstExpBits = dstBits - DST_SIG_BITS - 1;
|
||||
const int dstInfExp = (1 << dstExpBits) - 1;
|
||||
const int dstExpBias = dstInfExp >> 1;
|
||||
|
||||
const int underflowExponent = srcExpBias + 1 - dstExpBias;
|
||||
const int overflowExponent = srcExpBias + dstInfExp - dstExpBias;
|
||||
const SRC_REP_T underflow = (SRC_REP_T)underflowExponent << SRC_SIG_BITS;
|
||||
const SRC_REP_T overflow = (SRC_REP_T)overflowExponent << SRC_SIG_BITS;
|
||||
|
||||
const DST_REP_T dstQNaN = DST_REP_T(1) << (DST_SIG_BITS - 1);
|
||||
const DST_REP_T dstNaNCode = dstQNaN - 1;
|
||||
|
||||
// Break a into a sign and representation of the absolute value
|
||||
union SrcExchangeType {
|
||||
SRC_T f;
|
||||
SRC_REP_T i;
|
||||
};
|
||||
SrcExchangeType src_rep;
|
||||
src_rep.f = a;
|
||||
const SRC_REP_T aRep = src_rep.i;
|
||||
const SRC_REP_T aAbs = aRep & srcAbsMask;
|
||||
const SRC_REP_T sign = aRep & srcSignMask;
|
||||
DST_REP_T absResult;
|
||||
|
||||
if (aAbs - underflow < aAbs - overflow) {
|
||||
// The exponent of a is within the range of normal numbers in the
|
||||
// destination format. We can convert by simply right-shifting with
|
||||
// rounding and adjusting the exponent.
|
||||
absResult = aAbs >> (SRC_SIG_BITS - DST_SIG_BITS);
|
||||
absResult -= (DST_REP_T)(srcExpBias - dstExpBias) << DST_SIG_BITS;
|
||||
|
||||
const SRC_REP_T roundBits = aAbs & roundMask;
|
||||
// Round to nearest
|
||||
if (roundBits > halfway) absResult++;
|
||||
// Ties to even
|
||||
else if (roundBits == halfway)
|
||||
absResult += absResult & 1;
|
||||
} else if (aAbs > srcInfinity) {
|
||||
// a is NaN.
|
||||
// Conjure the result by beginning with infinity, setting the qNaN
|
||||
// bit and inserting the (truncated) trailing NaN field.
|
||||
absResult = (DST_REP_T)dstInfExp << DST_SIG_BITS;
|
||||
absResult |= dstQNaN;
|
||||
absResult |= ((aAbs & srcNaNCode) >> (SRC_SIG_BITS - DST_SIG_BITS)) & dstNaNCode;
|
||||
} else if (aAbs >= overflow) {
|
||||
// a overflows to infinity.
|
||||
absResult = (DST_REP_T)dstInfExp << DST_SIG_BITS;
|
||||
} else {
|
||||
// a underflows on conversion to the destination type or is an exact
|
||||
// zero. The result may be a denormal or zero. Extract the exponent
|
||||
// to get the shift amount for the denormalization.
|
||||
const int aExp = aAbs >> SRC_SIG_BITS;
|
||||
const int shift = srcExpBias - dstExpBias - aExp + 1;
|
||||
|
||||
const SRC_REP_T significand = (aRep & srcSignificandMask) | srcMinNormal;
|
||||
|
||||
// Right shift by the denormalization amount with sticky.
|
||||
if (shift > SRC_SIG_BITS) {
|
||||
absResult = 0;
|
||||
} else {
|
||||
const bool sticky = significand << (srcBits - shift);
|
||||
SRC_REP_T denormalizedSignificand = significand >> shift | sticky;
|
||||
absResult = denormalizedSignificand >> (SRC_SIG_BITS - DST_SIG_BITS);
|
||||
const SRC_REP_T roundBits = denormalizedSignificand & roundMask;
|
||||
// Round to nearest
|
||||
if (roundBits > halfway) absResult++;
|
||||
// Ties to even
|
||||
else if (roundBits == halfway)
|
||||
absResult += absResult & 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Apply the signbit to (DST_T)abs(a).
|
||||
const DST_REP_T result = absResult | sign >> (srcBits - dstBits);
|
||||
union DstExchangeType {
|
||||
DST_T f;
|
||||
DST_REP_T i;
|
||||
};
|
||||
DstExchangeType dst_rep;
|
||||
dst_rep.i = result;
|
||||
return dst_rep.f;
|
||||
}
|
||||
|
||||
template <typename SRC_T, typename SRC_REP_T, int SRC_SIG_BITS, typename DST_T, typename DST_REP_T,
|
||||
int DST_SIG_BITS>
|
||||
static inline DST_T __extendXfYf2__(SRC_T a) {
|
||||
// Various constants whose values follow from the type parameters.
|
||||
// Any reasonable optimizer will fold and propagate all of these.
|
||||
const int srcBits = sizeof(SRC_T) * 8;
|
||||
const int srcExpBits = srcBits - SRC_SIG_BITS - 1;
|
||||
const int srcInfExp = (1 << srcExpBits) - 1;
|
||||
const int srcExpBias = srcInfExp >> 1;
|
||||
|
||||
const SRC_REP_T srcMinNormal = SRC_REP_T(1) << SRC_SIG_BITS;
|
||||
const SRC_REP_T srcInfinity = (SRC_REP_T)srcInfExp << SRC_SIG_BITS;
|
||||
const SRC_REP_T srcSignMask = SRC_REP_T(1) << (SRC_SIG_BITS + srcExpBits);
|
||||
const SRC_REP_T srcAbsMask = srcSignMask - 1;
|
||||
const SRC_REP_T srcQNaN = SRC_REP_T(1) << (SRC_SIG_BITS - 1);
|
||||
const SRC_REP_T srcNaNCode = srcQNaN - 1;
|
||||
|
||||
const int dstBits = sizeof(DST_T) * 8;
|
||||
const int dstExpBits = dstBits - DST_SIG_BITS - 1;
|
||||
const int dstInfExp = (1 << dstExpBits) - 1;
|
||||
const int dstExpBias = dstInfExp >> 1;
|
||||
|
||||
const DST_REP_T dstMinNormal = DST_REP_T(1) << DST_SIG_BITS;
|
||||
|
||||
// Break a into a sign and representation of the absolute value
|
||||
union SrcExchangeType {
|
||||
SRC_T f;
|
||||
SRC_REP_T i;
|
||||
};
|
||||
SrcExchangeType src_rep;
|
||||
src_rep.f = a;
|
||||
const SRC_REP_T aRep = src_rep.i;
|
||||
const SRC_REP_T aAbs = aRep & srcAbsMask;
|
||||
const SRC_REP_T sign = aRep & srcSignMask;
|
||||
DST_REP_T absResult;
|
||||
|
||||
// If sizeof(SRC_REP_T) < sizeof(int), the subtraction result is promoted
|
||||
// to (signed) int. To avoid that, explicitly cast to SRC_REP_T.
|
||||
if ((SRC_REP_T)(aAbs - srcMinNormal) < srcInfinity - srcMinNormal) {
|
||||
// a is a normal number.
|
||||
// Extend to the destination type by shifting the significand and
|
||||
// exponent into the proper position and rebiasing the exponent.
|
||||
absResult = (DST_REP_T)aAbs << (DST_SIG_BITS - SRC_SIG_BITS);
|
||||
absResult += (DST_REP_T)(dstExpBias - srcExpBias) << DST_SIG_BITS;
|
||||
}
|
||||
|
||||
else if (aAbs >= srcInfinity) {
|
||||
// a is NaN or infinity.
|
||||
// Conjure the result by beginning with infinity, then setting the qNaN
|
||||
// bit (if needed) and right-aligning the rest of the trailing NaN
|
||||
// payload field.
|
||||
absResult = (DST_REP_T)dstInfExp << DST_SIG_BITS;
|
||||
absResult |= (DST_REP_T)(aAbs & srcQNaN) << (DST_SIG_BITS - SRC_SIG_BITS);
|
||||
absResult |= (DST_REP_T)(aAbs & srcNaNCode) << (DST_SIG_BITS - SRC_SIG_BITS);
|
||||
} else if (aAbs) {
|
||||
// a is denormal.
|
||||
// renormalize the significand and clear the leading bit, then insert
|
||||
// the correct adjusted exponent in the destination type.
|
||||
const int scale = __clz(aAbs) - __clz(srcMinNormal);
|
||||
absResult = (DST_REP_T)aAbs << (DST_SIG_BITS - SRC_SIG_BITS + scale);
|
||||
absResult ^= dstMinNormal;
|
||||
const int resultExponent = dstExpBias - srcExpBias - scale + 1;
|
||||
absResult |= (DST_REP_T)resultExponent << DST_SIG_BITS;
|
||||
} else {
|
||||
// a is zero.
|
||||
absResult = 0;
|
||||
}
|
||||
|
||||
// Apply the signbit to (DST_T)abs(a).
|
||||
const DST_REP_T result = absResult | (DST_REP_T)sign << (dstBits - srcBits);
|
||||
union DstExchangeType {
|
||||
DST_T f;
|
||||
DST_REP_T i;
|
||||
};
|
||||
DstExchangeType dst_rep;
|
||||
dst_rep.i = result;
|
||||
return dst_rep.f;
|
||||
}
|
||||
|
||||
#endif // COMPILER_RT_BUILTIN_FP16_H_
|
||||
+396
@@ -0,0 +1,396 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2024, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <cuda_bf16.h>
|
||||
#include <cuda_fp16.h>
|
||||
#include <dlpack/dlpack.h>
|
||||
#include <stdint.h>
|
||||
#include <tvm/runtime/logging.h>
|
||||
|
||||
#include "custom_allreduce_kernels.h"
|
||||
|
||||
namespace tensorrt_llm {
|
||||
|
||||
static inline __device__ void st_flag_release(uint32_t& flag, uint32_t* flag_addr) {
|
||||
#if __CUDA_ARCH__ >= 700
|
||||
asm volatile("st.global.release.sys.b32 [%1], %0;" ::"r"(flag), "l"(flag_addr));
|
||||
#else
|
||||
__threadfence_system();
|
||||
asm volatile("st.global.volatile.b32 [%1], %0;" ::"r"(flag), "l"(flag_addr));
|
||||
#endif
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static inline __device__ void ld_flag_acquire(uint32_t& flag, uint32_t* flag_addr) {
|
||||
#if __CUDA_ARCH__ >= 700
|
||||
asm volatile("ld.global.acquire.sys.b32 %0, [%1];" : "=r"(flag) : "l"(flag_addr));
|
||||
#else
|
||||
asm volatile("ld.global.volatile.b32 %0, [%1];" : "=r"(flag) : "l"(flag_addr));
|
||||
#endif
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Type Converter that packs data format to 128 bits data type
|
||||
//
|
||||
using PackedFloat = union {
|
||||
int4 packed;
|
||||
float unpacked[4];
|
||||
};
|
||||
|
||||
using PackedHalf = union {
|
||||
int4 packed;
|
||||
half2 unpacked[4];
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct PackedOn16Bytes {};
|
||||
|
||||
template <>
|
||||
struct PackedOn16Bytes<float> {
|
||||
using Type = PackedFloat;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct PackedOn16Bytes<half> {
|
||||
using Type = PackedHalf;
|
||||
};
|
||||
|
||||
using PackedBFloat16 = union {
|
||||
int4 packed;
|
||||
__nv_bfloat162 unpacked[4];
|
||||
};
|
||||
|
||||
template <>
|
||||
struct PackedOn16Bytes<__nv_bfloat16> {
|
||||
using Type = PackedBFloat16;
|
||||
};
|
||||
|
||||
// add two 128b data
|
||||
template <typename T>
|
||||
inline __device__ int4 add128b(T& a, T& b) {
|
||||
T c;
|
||||
c.unpacked[0] = a.unpacked[0] + b.unpacked[0];
|
||||
c.unpacked[1] = a.unpacked[1] + b.unpacked[1];
|
||||
c.unpacked[2] = a.unpacked[2] + b.unpacked[2];
|
||||
c.unpacked[3] = a.unpacked[3] + b.unpacked[3];
|
||||
return c.packed;
|
||||
}
|
||||
|
||||
__inline__ __device__ void multi_gpu_barrier(uint32_t** signals, const uint32_t flag,
|
||||
const size_t rank, const size_t world_size,
|
||||
int const tidx, int const bidx) {
|
||||
// At the end of the function, we now that has least block 0 from all others GPUs have reached
|
||||
// that point.
|
||||
uint32_t volatile* my_signals = signals[rank];
|
||||
if (tidx < world_size) {
|
||||
// The 1st block notifies the other ranks.
|
||||
if (bidx == 0) {
|
||||
signals[tidx][rank] = flag;
|
||||
}
|
||||
|
||||
// Busy-wait until all ranks are ready.
|
||||
while (my_signals[tidx] != flag) {
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure we can move on...
|
||||
__syncthreads();
|
||||
}
|
||||
|
||||
__global__ void multiGpuBarrierKernel(AllReduceParams params) {
|
||||
multi_gpu_barrier(params.peer_barrier_ptrs_out, params.barrier_flag, params.local_rank,
|
||||
params.ranks_per_node, threadIdx.x, blockIdx.x);
|
||||
}
|
||||
|
||||
template <typename T, int RANKS_PER_NODE>
|
||||
static __global__ void oneShotAllReduceKernel(AllReduceParams params) {
|
||||
int const bidx = blockIdx.x;
|
||||
int const tidx = threadIdx.x;
|
||||
|
||||
// The number of elements packed into one for comms
|
||||
static constexpr int NUM_ELTS = 16 / sizeof(T);
|
||||
|
||||
// Packed data type for comms
|
||||
using PackedStruct = typename PackedOn16Bytes<T>::Type;
|
||||
|
||||
multi_gpu_barrier(params.peer_barrier_ptrs_in, params.barrier_flag, params.local_rank,
|
||||
RANKS_PER_NODE, tidx, bidx);
|
||||
|
||||
// The source pointers. Distributed round-robin for the different warps.
|
||||
T const* src_d[RANKS_PER_NODE];
|
||||
#pragma unroll
|
||||
for (int ii = 0; ii < RANKS_PER_NODE; ++ii) {
|
||||
int rank = (params.local_rank + ii) % RANKS_PER_NODE;
|
||||
src_d[ii] = reinterpret_cast<T*>(params.peer_comm_buffer_ptrs[rank]);
|
||||
}
|
||||
|
||||
// The location in the destination array (load 8 fp16 or load 4 fp32 using LDG.128).
|
||||
size_t offset = bidx * params.elts_per_block + tidx * NUM_ELTS;
|
||||
// The end of the segment computed by that block.
|
||||
size_t max_offset = min((bidx + 1) * params.elts_per_block, params.elts_per_rank);
|
||||
|
||||
// Each block accumulates the values from the different GPUs on the same node.
|
||||
for (size_t iter_offset = offset; iter_offset < max_offset;
|
||||
iter_offset += blockDim.x * NUM_ELTS) {
|
||||
// Iterate over the different ranks/devices on the node to load the values.
|
||||
PackedStruct vals[RANKS_PER_NODE];
|
||||
#pragma unroll
|
||||
for (int ii = 0; ii < RANKS_PER_NODE; ++ii) {
|
||||
vals[ii].packed = *reinterpret_cast<int4 const*>(&src_d[ii][iter_offset]);
|
||||
}
|
||||
|
||||
// Sum the values from the different ranks.
|
||||
PackedStruct sums;
|
||||
sums.packed = {0, 0, 0, 0};
|
||||
#pragma unroll
|
||||
for (int ii = 0; ii < RANKS_PER_NODE; ++ii) {
|
||||
sums.packed = add128b(sums, vals[ii]);
|
||||
}
|
||||
|
||||
// Store to the destination buffer.
|
||||
*reinterpret_cast<int4*>(&reinterpret_cast<T*>(params.local_output_buffer_ptr)[iter_offset]) =
|
||||
sums.packed;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, int RANKS_PER_NODE>
|
||||
static __global__ void twoShotAllReduceKernel(AllReduceParams params) {
|
||||
// The block index.
|
||||
int const bidx = blockIdx.x;
|
||||
// The thread index with the block.
|
||||
int const tidx = threadIdx.x;
|
||||
|
||||
// The number of elements packed into one for comms
|
||||
static constexpr int NUM_ELTS = 16 / sizeof(T);
|
||||
|
||||
// Packed data type for comms
|
||||
using PackedType = typename PackedOn16Bytes<T>::Type;
|
||||
|
||||
// The location in the destination array (load 8 fp16 or load 4 fp32 using LDG.128).
|
||||
const size_t block_offset = bidx * params.elts_per_block + tidx * NUM_ELTS;
|
||||
const size_t block_start = params.rank_offset + block_offset;
|
||||
// The end of the segment computed by that block.
|
||||
size_t max_offset =
|
||||
min(block_start + params.elts_per_block, params.rank_offset + params.elts_per_rank);
|
||||
|
||||
multi_gpu_barrier(params.peer_barrier_ptrs_in, params.barrier_flag, params.local_rank,
|
||||
RANKS_PER_NODE, tidx, bidx);
|
||||
|
||||
// The source pointers. Distributed round-robin for the different warps.
|
||||
T* src_d[RANKS_PER_NODE];
|
||||
// The destination ranks for round-robin gathering
|
||||
size_t dst_rank[RANKS_PER_NODE];
|
||||
#pragma unroll
|
||||
for (int ii = 0; ii < RANKS_PER_NODE; ++ii) {
|
||||
int rank = (params.local_rank + ii) % RANKS_PER_NODE;
|
||||
src_d[ii] = reinterpret_cast<T*>(params.peer_comm_buffer_ptrs[rank]);
|
||||
dst_rank[ii] = rank;
|
||||
}
|
||||
|
||||
// Each block accumulates the values from the different GPUs on the same node.
|
||||
for (size_t local_offset = block_start; local_offset < max_offset;
|
||||
local_offset += blockDim.x * NUM_ELTS) {
|
||||
// Iterate over the different ranks/devices on the node to load the values.
|
||||
PackedType vals[RANKS_PER_NODE];
|
||||
#pragma unroll
|
||||
for (int ii = 0; ii < RANKS_PER_NODE; ++ii) {
|
||||
vals[ii].packed = *reinterpret_cast<int4 const*>(&src_d[ii][local_offset]);
|
||||
}
|
||||
|
||||
// Sum the values from the different ranks.
|
||||
PackedType sums;
|
||||
sums.packed = {0, 0, 0, 0};
|
||||
#pragma unroll
|
||||
for (int ii = 0; ii < RANKS_PER_NODE; ++ii) {
|
||||
sums.packed = add128b(sums, vals[ii]);
|
||||
}
|
||||
|
||||
// Store to the local buffer.
|
||||
*reinterpret_cast<int4*>(&src_d[0][local_offset]) = sums.packed;
|
||||
}
|
||||
|
||||
// sync threads to make sure all block threads have the sums
|
||||
__syncthreads();
|
||||
|
||||
// barriers among the blocks with the same idx (release-acquire semantics)
|
||||
if (tidx < RANKS_PER_NODE) {
|
||||
// The all blocks notifies the other ranks.
|
||||
uint32_t flag_block_offset = RANKS_PER_NODE + bidx * RANKS_PER_NODE;
|
||||
st_flag_release(params.barrier_flag,
|
||||
params.peer_barrier_ptrs_in[tidx] + flag_block_offset + params.local_rank);
|
||||
|
||||
// Busy-wait until all ranks are ready.
|
||||
uint32_t rank_barrier = 0;
|
||||
uint32_t* peer_barrier_d =
|
||||
params.peer_barrier_ptrs_in[params.local_rank] + flag_block_offset + tidx;
|
||||
do {
|
||||
ld_flag_acquire(rank_barrier, peer_barrier_d);
|
||||
} while (rank_barrier != params.barrier_flag);
|
||||
}
|
||||
|
||||
// sync threads to make sure all other ranks has the final partial results
|
||||
__syncthreads();
|
||||
|
||||
size_t max_block_offset = min(block_offset + params.elts_per_block, params.elts_per_rank);
|
||||
// Gather all needed elts from other intra-node ranks
|
||||
for (size_t local_offset = block_offset; local_offset < max_block_offset;
|
||||
local_offset += blockDim.x * NUM_ELTS) {
|
||||
#pragma unroll
|
||||
for (int ii = 0; ii < RANKS_PER_NODE; ++ii) {
|
||||
// use round-robin gathering from other ranks
|
||||
size_t offset_rank = dst_rank[ii] * params.elts_per_rank + local_offset;
|
||||
if (offset_rank >= params.elts_total) {
|
||||
continue;
|
||||
}
|
||||
*reinterpret_cast<int4*>(&reinterpret_cast<T*>(params.local_output_buffer_ptr)[offset_rank]) =
|
||||
*reinterpret_cast<int4*>(&src_d[ii][offset_rank]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline int divUp(int a, int b) { return (a + b - 1) / b; }
|
||||
|
||||
std::tuple<int, int> kernelLaunchConfig(AllReduceStrategyType algo, AllReduceParams& param,
|
||||
size_t elts_per_thread) {
|
||||
TVM_FFI_ICHECK(param.elts_total % elts_per_thread == 0);
|
||||
|
||||
int blocks_per_grid = 1, threads_per_block = DEFAULT_BLOCK_SIZE;
|
||||
|
||||
const size_t total_threads = param.elts_total / elts_per_thread;
|
||||
switch (algo) {
|
||||
case AllReduceStrategyType::ONESHOT: { // one stage all reduce algo
|
||||
if (total_threads <= DEFAULT_BLOCK_SIZE) { // local reduce
|
||||
threads_per_block = WARP_SIZE * divUp(total_threads, WARP_SIZE);
|
||||
blocks_per_grid = 1;
|
||||
} else { // local reduce
|
||||
threads_per_block = DEFAULT_BLOCK_SIZE;
|
||||
blocks_per_grid = divUp(total_threads, DEFAULT_BLOCK_SIZE);
|
||||
blocks_per_grid = std::min(static_cast<int>(MAX_ALL_REDUCE_BLOCKS), blocks_per_grid);
|
||||
}
|
||||
param.elts_per_rank = param.elts_total;
|
||||
param.elts_per_block =
|
||||
elts_per_thread * divUp(param.elts_per_rank, elts_per_thread * blocks_per_grid);
|
||||
break;
|
||||
}
|
||||
case AllReduceStrategyType::TWOSHOT: { // two stage all reduce algo
|
||||
const size_t elts_per_rank = param.elts_total / param.ranks_per_node;
|
||||
TVM_FFI_ICHECK(elts_per_rank % elts_per_thread == 0);
|
||||
|
||||
size_t total_threads = elts_per_rank / elts_per_thread;
|
||||
total_threads = WARP_SIZE * ((total_threads + WARP_SIZE - 1) / WARP_SIZE);
|
||||
TVM_FFI_ICHECK(total_threads % WARP_SIZE == 0);
|
||||
|
||||
while (total_threads % blocks_per_grid != 0 ||
|
||||
total_threads / blocks_per_grid > DEFAULT_BLOCK_SIZE) {
|
||||
blocks_per_grid += 1;
|
||||
}
|
||||
|
||||
threads_per_block = total_threads / blocks_per_grid;
|
||||
|
||||
// NOTE: need to adjust here
|
||||
if (static_cast<size_t>(blocks_per_grid) > MAX_ALL_REDUCE_BLOCKS) {
|
||||
size_t iter_factor = 1;
|
||||
while (blocks_per_grid / iter_factor > MAX_ALL_REDUCE_BLOCKS ||
|
||||
blocks_per_grid % iter_factor) {
|
||||
iter_factor += 1;
|
||||
}
|
||||
blocks_per_grid /= iter_factor;
|
||||
}
|
||||
param.elts_per_rank = param.elts_total / param.ranks_per_node;
|
||||
param.elts_per_block = param.elts_per_rank / blocks_per_grid;
|
||||
param.elts_per_block = elts_per_thread * divUp(param.elts_per_block, elts_per_thread);
|
||||
param.rank_offset = param.rank * param.elts_per_rank;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
LOG(FATAL) << ("Algorithm not supported here.");
|
||||
}
|
||||
|
||||
return std::make_tuple(blocks_per_grid, threads_per_block);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <typename T, int RANKS_PER_NODE>
|
||||
void dispatchARKernels(AllReduceStrategyType algo, AllReduceParams& param, int blocks_per_grid,
|
||||
int threads_per_block, cudaStream_t stream) {
|
||||
if (algo == AllReduceStrategyType::ONESHOT) {
|
||||
oneShotAllReduceKernel<T, RANKS_PER_NODE>
|
||||
<<<blocks_per_grid, threads_per_block, 0, stream>>>(param);
|
||||
} else {
|
||||
twoShotAllReduceKernel<T, RANKS_PER_NODE>
|
||||
<<<blocks_per_grid, threads_per_block, 0, stream>>>(param);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void invokeOneOrTwoShotAllReduceKernel(AllReduceParams& param, AllReduceStrategyType strat,
|
||||
cudaStream_t stream) {
|
||||
TVM_FFI_ICHECK(strat == AllReduceStrategyType::ONESHOT || strat == AllReduceStrategyType::TWOSHOT);
|
||||
auto last_error = cudaGetLastError();
|
||||
if (last_error != cudaSuccess) {
|
||||
LOG(INFO) << "cuda error:" << cudaGetErrorString(last_error);
|
||||
}
|
||||
|
||||
size_t elts_per_thread = 16 / sizeof(T);
|
||||
auto [blocks_per_grid, threads_per_block] = kernelLaunchConfig(strat, param, elts_per_thread);
|
||||
switch (param.ranks_per_node) {
|
||||
case 2:
|
||||
dispatchARKernels<T, 2>(strat, param, blocks_per_grid, threads_per_block, stream);
|
||||
break;
|
||||
case 4:
|
||||
dispatchARKernels<T, 4>(strat, param, blocks_per_grid, threads_per_block, stream);
|
||||
break;
|
||||
case 6:
|
||||
dispatchARKernels<T, 6>(strat, param, blocks_per_grid, threads_per_block, stream);
|
||||
break;
|
||||
case 8:
|
||||
dispatchARKernels<T, 8>(strat, param, blocks_per_grid, threads_per_block, stream);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
last_error = cudaGetLastError();
|
||||
if (last_error != cudaSuccess) {
|
||||
LOG(INFO) << "cuda error:" << cudaGetErrorString(last_error);
|
||||
}
|
||||
}
|
||||
|
||||
void invokeMultiGpuBarrier(AllReduceParams& param, cudaStream_t stream) {
|
||||
multiGpuBarrierKernel<<<1, param.ranks_per_node, 0, stream>>>(param);
|
||||
}
|
||||
|
||||
void customAllReduce(AllReduceParams& params, void* data, size_t elts, DLDataType dataType,
|
||||
AllReduceStrategyType strat, cudaStream_t stream) {
|
||||
params.local_output_buffer_ptr = data;
|
||||
params.elts_total = elts;
|
||||
|
||||
if (dataType.code == kDLFloat && dataType.bits == 32) {
|
||||
invokeOneOrTwoShotAllReduceKernel<float>(params, strat, stream);
|
||||
} else if (dataType.code == kDLFloat && dataType.bits == 16) {
|
||||
invokeOneOrTwoShotAllReduceKernel<half>(params, strat, stream);
|
||||
} else if (dataType.code == kDLBfloat && dataType.bits == 16) {
|
||||
invokeOneOrTwoShotAllReduceKernel<__nv_bfloat16>(params, strat, stream);
|
||||
} else {
|
||||
LOG(FATAL) << ("Unsupported dataType for customAllReduce");
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace tensorrt_llm
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2024, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <cuda_fp16.h>
|
||||
#include <stdint.h>
|
||||
|
||||
namespace tensorrt_llm {
|
||||
|
||||
constexpr size_t WARP_SIZE = 32;
|
||||
constexpr size_t MAX_ALL_REDUCE_BLOCKS = 24;
|
||||
constexpr size_t MAX_RANKS_PER_NODE = 8;
|
||||
constexpr size_t DEFAULT_BLOCK_SIZE = 1024;
|
||||
|
||||
enum class AllReduceStrategyType : int8_t {
|
||||
RING = 0,
|
||||
ONESHOT = 1,
|
||||
TWOSHOT = 2,
|
||||
AUTO = 3,
|
||||
};
|
||||
|
||||
struct AllReduceParams {
|
||||
size_t elts_total;
|
||||
size_t elts_per_rank;
|
||||
size_t elts_per_block;
|
||||
size_t rank_offset;
|
||||
size_t ranks_per_node, rank, local_rank;
|
||||
uint32_t barrier_flag;
|
||||
uint32_t* peer_barrier_ptrs_in[MAX_RANKS_PER_NODE];
|
||||
uint32_t* peer_barrier_ptrs_out[MAX_RANKS_PER_NODE];
|
||||
void* peer_comm_buffer_ptrs[MAX_RANKS_PER_NODE];
|
||||
void* local_output_buffer_ptr;
|
||||
};
|
||||
|
||||
inline size_t GetMaxRequiredWorkspaceSize(int world_size) {
|
||||
if (world_size <= 2) {
|
||||
return 16 * 1000 * 1000;
|
||||
}
|
||||
return 8 * 1000 * 1000;
|
||||
}
|
||||
|
||||
inline AllReduceStrategyType SelectImplementation(size_t message_size, int world_size) {
|
||||
const size_t maxWorkspaceSize = GetMaxRequiredWorkspaceSize(world_size);
|
||||
|
||||
if (message_size > maxWorkspaceSize) {
|
||||
return AllReduceStrategyType::RING;
|
||||
}
|
||||
|
||||
if (world_size <= 2) {
|
||||
return AllReduceStrategyType::ONESHOT;
|
||||
}
|
||||
|
||||
if (world_size <= 4) {
|
||||
if (message_size < 1 * 1000 * 1000) {
|
||||
return AllReduceStrategyType::ONESHOT;
|
||||
}
|
||||
return AllReduceStrategyType::TWOSHOT;
|
||||
}
|
||||
|
||||
if (message_size < 500 * 1000) {
|
||||
return AllReduceStrategyType::ONESHOT;
|
||||
}
|
||||
return AllReduceStrategyType::TWOSHOT;
|
||||
}
|
||||
|
||||
void customAllReduce(AllReduceParams& params, void* data, size_t elts, DLDataType dataType,
|
||||
AllReduceStrategyType strat, cudaStream_t stream);
|
||||
|
||||
} // namespace tensorrt_llm
|
||||
@@ -0,0 +1,99 @@
|
||||
<!--
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
-->
|
||||
|
||||
# AGENTS.md
|
||||
|
||||
This file provides vendor-neutral guidance for agentic coding tools working
|
||||
with Apache TVM.
|
||||
|
||||
## Repository Overview
|
||||
|
||||
Apache TVM is an open-source machine learning compiler stack. The repository
|
||||
contains the C++ compiler/runtime, Python bindings, TIR/Relax IRs, scheduling
|
||||
and lowering passes, target code generators, runtime integrations, tests,
|
||||
documentation, and application examples.
|
||||
|
||||
## Repository Structure
|
||||
|
||||
- `include/tvm/` - public C++ headers
|
||||
- `src/` - C++ implementation
|
||||
- `python/tvm/` - Python package
|
||||
- `tests/` - C++, Python, integration, and lint tests
|
||||
- `cmake/` - CMake modules and default configuration
|
||||
- `3rdparty/` - vendored dependencies and submodules
|
||||
- `docs/` - documentation source
|
||||
- `apps/` - application examples
|
||||
- `.agents/skills/` - reusable agent workflows for this repository
|
||||
|
||||
## Build
|
||||
|
||||
Use an existing `build/` directory when present:
|
||||
|
||||
```bash
|
||||
cmake --build build --parallel
|
||||
```
|
||||
|
||||
For a fresh checkout, initialize submodules and configure CMake first:
|
||||
|
||||
```bash
|
||||
git submodule update --init --recursive
|
||||
mkdir -p build
|
||||
cp cmake/config.cmake build/config.cmake
|
||||
cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
cmake --build build --parallel
|
||||
```
|
||||
|
||||
Development should use `PYTHONPATH`, not editable installs:
|
||||
|
||||
```bash
|
||||
export PYTHONPATH="$(pwd)/python:$(pwd)/.local/python"
|
||||
```
|
||||
|
||||
Do not use `pip install -e` for TVM or `tvm-ffi`; editable installs can make
|
||||
one worktree silently import another worktree's code.
|
||||
|
||||
## Test And Lint
|
||||
|
||||
Run the smallest relevant test first, then broaden as needed. Common examples:
|
||||
|
||||
```bash
|
||||
python -m pytest tests/python/all-platform-minimal-test/ -xvs
|
||||
python -m pytest tests/python/tir-base/test_tir_base.py -xvs
|
||||
./build/cpptest
|
||||
```
|
||||
|
||||
For lint validation on a pull request, run pre-commit on the files changed by
|
||||
the branch instead of the whole repository:
|
||||
|
||||
```bash
|
||||
pre-commit run --files <changed-file>...
|
||||
```
|
||||
|
||||
Use `python -m tirx_kernels.bench_suite` in the **tirx-kernels** repo
|
||||
(`tirx_kernels/bench_suite/`) when that workflow applies.
|
||||
|
||||
## Coding Conventions
|
||||
|
||||
- Follow the surrounding style before introducing new abstractions.
|
||||
- Keep changes scoped to the task and avoid unrelated cleanups.
|
||||
- Prefer explicit tests that show the IR or behavior being changed.
|
||||
- Use Apache TVM commit tags such as `[REFACTOR][IR]`, `[FIX][TIR]`, or
|
||||
`[DOCS]` as appropriate.
|
||||
- Preserve Apache license headers in new source, script, and documentation
|
||||
files when the surrounding tree uses them.
|
||||
+958
@@ -0,0 +1,958 @@
|
||||
cmake_minimum_required(VERSION 3.18)
|
||||
project(tvm C CXX)
|
||||
|
||||
# --- TVM version (no dependency on version.py) ---
|
||||
# When built via scikit-build-core the version is resolved by setuptools_scm and
|
||||
# passed in as SKBUILD_PROJECT_VERSION_FULL; bake it into the C++ TVM_VERSION macro.
|
||||
# A bare `cmake` build (no scikit-build-core) leaves the checked-in default in
|
||||
# include/tvm/runtime/base.h untouched. An explicit -DTVM_VERSION always wins.
|
||||
if(NOT DEFINED TVM_VERSION AND DEFINED SKBUILD_PROJECT_VERSION_FULL)
|
||||
set(TVM_VERSION "${SKBUILD_PROJECT_VERSION_FULL}")
|
||||
endif()
|
||||
if(DEFINED TVM_VERSION)
|
||||
message(STATUS "TVM_VERSION=${TVM_VERSION}")
|
||||
add_compile_definitions(TVM_VERSION="${TVM_VERSION}")
|
||||
endif()
|
||||
|
||||
# Utility functions
|
||||
include(cmake/utils/Utils.cmake)
|
||||
include(cmake/utils/Summary.cmake)
|
||||
include(cmake/utils/Linker.cmake)
|
||||
include(cmake/utils/Library.cmake)
|
||||
include(cmake/utils/FindCUDA.cmake)
|
||||
include(cmake/utils/FindNCCL.cmake)
|
||||
include(cmake/utils/FindOpenCL.cmake)
|
||||
include(cmake/utils/FindVulkan.cmake)
|
||||
include(cmake/utils/FindLLVM.cmake)
|
||||
include(cmake/utils/FindROCM.cmake)
|
||||
include(cmake/utils/FindRCCL.cmake)
|
||||
include(cmake/utils/FindNVSHMEM.cmake)
|
||||
|
||||
if(EXISTS ${CMAKE_BINARY_DIR}/config.cmake)
|
||||
include(${CMAKE_BINARY_DIR}/config.cmake)
|
||||
else()
|
||||
if(EXISTS ${CMAKE_SOURCE_DIR}/config.cmake)
|
||||
include(${CMAKE_SOURCE_DIR}/config.cmake)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# NOTE: do not modify this file to change option values.
|
||||
# You can create a config.cmake at build folder
|
||||
# and add set(OPTION VALUE) to override these build options.
|
||||
# Alernatively, use cmake -DOPTION=VALUE through command-line.
|
||||
tvm_option(USE_CUDA "Build with CUDA" OFF)
|
||||
tvm_option(USE_NCCL "Build with NCCL" OFF)
|
||||
tvm_option(USE_OPENCL "Build with OpenCL" OFF)
|
||||
tvm_option(USE_OPENCL_ENABLE_HOST_PTR "Enable OpenCL memory object access to host" OFF)
|
||||
tvm_option(USE_OPENCL_GTEST "Path to OpenCL specific gtest version for runtime cpp tests." /path/to/opencl/gtest)
|
||||
tvm_option(USE_VULKAN "Build with Vulkan" OFF)
|
||||
|
||||
|
||||
# Whether to use spirv-tools and SPIRV-Headers from Khronos GitHub or GitLab.
|
||||
#
|
||||
# Possible values:
|
||||
# - OFF: not to use
|
||||
# - /path/to/install: path to your khronis spirv-tools and SPIRV-Headers installation directory
|
||||
#
|
||||
tvm_option(USE_KHRONOS_SPIRV "Whether to use spirv-tools and SPIRV-Headers from Khronos GitHub or GitLab" OFF)
|
||||
tvm_option(USE_SPIRV_KHR_INTEGER_DOT_PRODUCT "whether enable SPIRV_KHR_DOT_PRODUCT" OFF)
|
||||
tvm_option(USE_METAL "Build with Metal" OFF)
|
||||
tvm_option(USE_ROCM "Build with ROCM" OFF)
|
||||
tvm_option(USE_RCCL "Build with RCCL" OFF)
|
||||
tvm_option(ROCM_PATH "The path to rocm" /opt/rocm)
|
||||
tvm_option(USE_HEXAGON "Build with Hexagon support" OFF)
|
||||
tvm_option(USE_HEXAGON_SDK "Path to the Hexagon SDK root (required for Hexagon support)" /path/to/sdk)
|
||||
tvm_option(USE_HEXAGON_RPC "Enable Hexagon RPC using minRPC implementation over Android." OFF)
|
||||
tvm_option(USE_HEXAGON_GTEST "Path to Hexagon specific gtest version for runtime cpp tests." /path/to/hexagon/gtest)
|
||||
tvm_option(USE_HEXAGON_EXTERNAL_LIBS "Path to git repo containing external Hexagon runtime sources or libraries" OFF)
|
||||
|
||||
tvm_option(USE_RPC "Build with RPC" ON)
|
||||
tvm_option(USE_THREADS "Build with thread support" ON)
|
||||
tvm_option(USE_LLVM "Build with LLVM, can be set to specific llvm-config path" OFF)
|
||||
tvm_option(USE_MLIR "Build with MLIR support" OFF)
|
||||
tvm_option(USE_OPENMP "Build with OpenMP thread pool implementation" OFF)
|
||||
tvm_option(TVM_DEBUG_WITH_ABI_CHANGE "Enable debug code that may cause ABI changes" OFF)
|
||||
tvm_option(TVM_LOG_BEFORE_THROW "Whether log before throw, for debugging purposes" OFF)
|
||||
tvm_option(USE_RTTI "Build with RTTI" ON)
|
||||
tvm_option(USE_MSVC_MT "Build with MT" OFF)
|
||||
tvm_option(INSTALL_DEV "Install compiler infrastructure" OFF)
|
||||
tvm_option(HIDE_PRIVATE_SYMBOLS "Compile with -fvisibility=hidden." ON)
|
||||
tvm_option(INDEX_DEFAULT_I64 "Defaults the index datatype to int64" ON)
|
||||
tvm_option(BUILD_STATIC_RUNTIME "Build static version of libtvm_runtime" OFF)
|
||||
tvm_option(USE_GTEST "Use GoogleTest for C++ sanity tests" AUTO)
|
||||
tvm_option(USE_CUSTOM_LOGGING "Use user-defined custom logging, tvm::runtime::detail::LogFatalImpl and tvm::runtime::detail::LogMessageImpl must be implemented" OFF)
|
||||
tvm_option(USE_ALTERNATIVE_LINKER "Use 'mold' or 'lld' if found when invoking compiler to link artifact" AUTO)
|
||||
tvm_option(USE_CCACHE "Use ccache if found when invoking compiler" AUTO)
|
||||
|
||||
# 3rdparty libraries
|
||||
tvm_option(COMPILER_RT_PATH "Path to COMPILER-RT" "3rdparty/compiler-rt")
|
||||
# Contrib library options
|
||||
tvm_option(USE_BLAS "The blas library to be linked" none)
|
||||
tvm_option(USE_AMX "Enable Intel AMX" OFF)
|
||||
tvm_option(USE_Z3 "Build with Z3 SMT solver support" OFF)
|
||||
tvm_option(USE_MKL "MKL root path when use MKL blas" OFF)
|
||||
tvm_option(USE_DNNL "Enable DNNL codegen" OFF)
|
||||
tvm_option(USE_CUDNN "Build with cuDNN" OFF)
|
||||
tvm_option(USE_CUBLAS "Build with cuBLAS" OFF)
|
||||
tvm_option(USE_NVTX "Build with NVTX" OFF)
|
||||
tvm_option(USE_CUTLASS "Build with CUTLASS" OFF)
|
||||
tvm_option(USE_THRUST "Build with Thrust" OFF)
|
||||
tvm_option(USE_CURAND "Build with cuRAND" OFF)
|
||||
tvm_option(USE_HIPBLAS "Build with ROCM:HIPBLAS" OFF)
|
||||
tvm_option(USE_SORT "Build with sort support" ON)
|
||||
tvm_option(USE_RANDOM "Build with random support" ON)
|
||||
tvm_option(USE_CPP_RPC "Build CPP RPC" OFF)
|
||||
tvm_option(USE_IOS_RPC "Build iOS RPC" OFF)
|
||||
tvm_option(USE_COREML "Build with coreml support" OFF)
|
||||
tvm_option(USE_TENSORRT_CODEGEN "Build with TensorRT Codegen support" OFF)
|
||||
tvm_option(USE_TENSORRT_RUNTIME "Build with TensorRT runtime" OFF)
|
||||
tvm_option(USE_NNAPI_CODEGEN "Build with NNAPI Codegen support" OFF)
|
||||
tvm_option(USE_NNAPI_RUNTIME "Build with NNAPI runtime" OFF)
|
||||
tvm_option(USE_EXAMPLE_NPU_CODEGEN "Build with Example NPU Codegen support" OFF)
|
||||
tvm_option(USE_EXAMPLE_NPU_RUNTIME "Build with Example NPU runtime" OFF)
|
||||
tvm_option(SUMMARIZE "Print CMake option summary after configuring" OFF)
|
||||
tvm_option(USE_CLML "Build with CLML Codegen support" OFF)
|
||||
tvm_option(USE_CLML_GRAPH_EXECUTOR "Build with CLML graph runtime" OFF)
|
||||
tvm_option(USE_NVSHMEM "Build with NVSHMEM support" OFF)
|
||||
|
||||
# Python package options
|
||||
tvm_option(TVM_BUILD_PYTHON_MODULE "Build Python module with scikit-build-core" OFF)
|
||||
|
||||
# include directories
|
||||
include_directories(${CMAKE_INCLUDE_PATH})
|
||||
include_directories("include")
|
||||
include_directories(SYSTEM ${COMPILER_RT_PATH})
|
||||
|
||||
# initial variables
|
||||
set(TVM_LINKER_LIBS "")
|
||||
set(TVM_RUNTIME_LINKER_LIBS "")
|
||||
set(TVM_RUNTIME_BACKEND_LIBS "")
|
||||
# Early target creation so contrib cmake files can call
|
||||
# target_link_libraries(tvm_runtime_extra PRIVATE <object_lib>) directly.
|
||||
add_library(tvm_runtime_extra SHARED)
|
||||
list(APPEND TVM_RUNTIME_BACKEND_LIBS tvm_runtime_extra)
|
||||
set_target_properties(tvm_runtime_extra PROPERTIES LINKER_LANGUAGE CXX)
|
||||
# INTERFACE target carrying compile definitions for OBJECT libs that build
|
||||
# into tvm_runtime_extra. On MSVC, TVM_RUNTIME_EXPORTS makes TVM_RUNTIME_DLL
|
||||
# expand to __declspec(dllexport) so that functions defined in extra modules
|
||||
# are properly exported from tvm_runtime_extra.dll.
|
||||
add_library(tvm_runtime_extra_defs INTERFACE)
|
||||
target_link_libraries(tvm_runtime_extra_defs INTERFACE tvm_ffi_header)
|
||||
target_compile_definitions(tvm_runtime_extra_defs
|
||||
INTERFACE TVM_RUNTIME_EXPORTS TVM_FFI_EXPORTS)
|
||||
|
||||
|
||||
# Check if this is being run on its own or as a subdirectory for another project
|
||||
# If we update to CMake 2.21+, we can use PROJECT_IS_TOP_LEVEL instead
|
||||
get_directory_property(IS_SUBPROJECT PARENT_DIRECTORY)
|
||||
|
||||
if(NOT IS_SUBPROJECT AND NOT DEFINED "${CMAKE_EXPORT_COMPILE_COMMANDS}")
|
||||
# If not set manually, change the default to ON
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||
endif()
|
||||
|
||||
if(TVM_LOG_BEFORE_THROW)
|
||||
# log error before throw as
|
||||
# when system have issues with stack trace
|
||||
add_definitions(-DTVM_LOG_BEFORE_THROW=1)
|
||||
endif()
|
||||
|
||||
# Generic compilation options
|
||||
if(MSVC)
|
||||
add_definitions(-DWIN32_LEAN_AND_MEAN)
|
||||
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
|
||||
add_definitions(-D_SCL_SECURE_NO_WARNINGS)
|
||||
add_definitions(-D_ENABLE_EXTENDED_ALIGNED_STORAGE)
|
||||
add_definitions(-DNOMINMAX)
|
||||
# regeneration does not work well with msbuild custom rules.
|
||||
set(CMAKE_SUPPRESS_REGENERATION ON)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /EHsc")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP")
|
||||
add_compile_options(/bigobj)
|
||||
|
||||
# Use standard-conforming two-phase name resolution for templates.
|
||||
# This minimizes the differences between g++/clang builds on Linux,
|
||||
# and MSVC builds on Windows.
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /permissive-")
|
||||
|
||||
# MSVC already errors on undefined symbols, no additional flag needed.
|
||||
set(TVM_NO_UNDEFINED_SYMBOLS "")
|
||||
|
||||
if(USE_MSVC_MT)
|
||||
foreach(flag_var
|
||||
CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE
|
||||
CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO)
|
||||
if(${flag_var} MATCHES "/MD")
|
||||
string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}")
|
||||
endif(${flag_var} MATCHES "/MD")
|
||||
endforeach(flag_var)
|
||||
# Static linking. CMake behavior changed in 3.15 making this necessary.
|
||||
add_compile_options(/MT)
|
||||
endif()
|
||||
# Disable common MSVC warnings
|
||||
# Integer conversion warnings(e.g. int64 to int)
|
||||
add_compile_options(/wd4244)
|
||||
add_compile_options(/wd4267)
|
||||
# Signed unsigned constant comparison
|
||||
add_compile_options(/wd4018)
|
||||
# Aligned alloc may not met(need c++17)
|
||||
add_compile_options(/wd4316)
|
||||
# unreferenced local variables(usually in exception catch)
|
||||
add_compile_options(/wd4101)
|
||||
# always inline keyword not necessary
|
||||
add_compile_options(/wd4180)
|
||||
# DLL interface warning in c++
|
||||
add_compile_options(/wd4251)
|
||||
# destructor was implicitly defined as deleted
|
||||
add_compile_options(/wd4624)
|
||||
# unary minus operator applied to unsigned type, result still unsigned
|
||||
add_compile_options(/wd4146)
|
||||
# 'inline': used more than once
|
||||
add_compile_options(/wd4141)
|
||||
# unknown pragma
|
||||
add_compile_options(/wd4068)
|
||||
else(MSVC)
|
||||
set(WARNING_FLAG -Wall)
|
||||
if ("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
|
||||
message(STATUS "Build in Debug mode")
|
||||
set(CMAKE_C_FLAGS "-O0 -g ${WARNING_FLAG} -fPIC ${CMAKE_C_FLAGS}")
|
||||
set(CMAKE_CXX_FLAGS "-O0 -g ${WARNING_FLAG} -fPIC ${CMAKE_CXX_FLAGS}")
|
||||
set(CMAKE_CUDA_FLAGS "-O0 -g -Xcompiler=-Wall -Xcompiler=-fPIC ${CMAKE_CUDA_FLAGS}")
|
||||
else()
|
||||
set(CMAKE_C_FLAGS "-O2 ${WARNING_FLAG} -fPIC ${CMAKE_C_FLAGS}")
|
||||
set(CMAKE_CXX_FLAGS "-O2 ${WARNING_FLAG} -fPIC ${CMAKE_CXX_FLAGS}")
|
||||
set(CMAKE_CUDA_FLAGS "-O2 -Xcompiler=-Wall -Xcompiler=-fPIC ${CMAKE_CUDA_FLAGS}")
|
||||
set(TVM_VISIBILITY_FLAG "")
|
||||
if (HIDE_PRIVATE_SYMBOLS)
|
||||
message(STATUS "Hide private symbols...")
|
||||
set(TVM_VISIBILITY_FLAG "-fvisibility=hidden")
|
||||
endif(HIDE_PRIVATE_SYMBOLS)
|
||||
endif ()
|
||||
if (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang" AND
|
||||
CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 7.0)
|
||||
set(CMAKE_CXX_FLAGS "-faligned-new ${CMAKE_CXX_FLAGS}")
|
||||
endif()
|
||||
|
||||
# ld option to warn if symbols are undefined (e.g. libtvm_runtime.so
|
||||
# using symbols only present in libtvm.so). Not needed for MSVC,
|
||||
# since this is already the default there.
|
||||
if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin" OR ${CMAKE_SYSTEM_NAME} MATCHES "iOS")
|
||||
set(TVM_NO_UNDEFINED_SYMBOLS "-Wl,-undefined,error")
|
||||
else()
|
||||
set(TVM_NO_UNDEFINED_SYMBOLS "-Wl,--no-undefined")
|
||||
endif()
|
||||
message(STATUS "Forbidding undefined symbols in shared library, using ${TVM_NO_UNDEFINED_SYMBOLS} on platform ${CMAKE_SYSTEM_NAME}")
|
||||
|
||||
# Detect if we're compiling for Hexagon.
|
||||
set(TEST_FOR_HEXAGON_CXX
|
||||
"#ifndef __hexagon__"
|
||||
"#error"
|
||||
"#endif"
|
||||
"int main() {}"
|
||||
# Define _start_main to avoid linking errors with -fPIC.
|
||||
"extern \"C\" void _start_main() {}")
|
||||
set(TEST_FOR_HEXAGON_DIR
|
||||
"${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp")
|
||||
set(TEST_FOR_HEXAGON_FILE "${TEST_FOR_HEXAGON_DIR}/test_for_hexagon.cc")
|
||||
string(REPLACE ";" "\n" TEST_FOR_HEXAGON_CXX_TEXT "${TEST_FOR_HEXAGON_CXX}")
|
||||
file(WRITE "${TEST_FOR_HEXAGON_FILE}" "${TEST_FOR_HEXAGON_CXX_TEXT}")
|
||||
try_compile(BUILD_FOR_HEXAGON "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}"
|
||||
"${TEST_FOR_HEXAGON_FILE}")
|
||||
file(REMOVE "${TEST_FOR_HEXAGON_FILE}")
|
||||
if(BUILD_FOR_HEXAGON)
|
||||
message(STATUS "Building for Hexagon")
|
||||
endif()
|
||||
|
||||
# Detect if we're compiling for Android.
|
||||
set(TEST_FOR_ANDROID_CXX
|
||||
"#ifndef __ANDROID__"
|
||||
"#error"
|
||||
"#endif"
|
||||
"int main() {}")
|
||||
set(TEST_FOR_ANDROID_DIR
|
||||
"${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp")
|
||||
set(TEST_FOR_ANDROID_FILE "${TEST_FOR_ANDROID_DIR}/test_for_android.cc")
|
||||
string(REPLACE ";" "\n" TEST_FOR_ANDROID_CXX_TEXT "${TEST_FOR_ANDROID_CXX}")
|
||||
file(WRITE "${TEST_FOR_ANDROID_FILE}" "${TEST_FOR_ANDROID_CXX_TEXT}")
|
||||
try_compile(BUILD_FOR_ANDROID "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}"
|
||||
"${TEST_FOR_ANDROID_FILE}")
|
||||
file(REMOVE "${TEST_FOR_ANDROID_FILE}")
|
||||
if(BUILD_FOR_ANDROID)
|
||||
message(STATUS "Building for Android")
|
||||
endif()
|
||||
endif(MSVC)
|
||||
|
||||
# Hexagon has dlopen built into QuRT (no need for static library).
|
||||
if(NOT BUILD_FOR_HEXAGON)
|
||||
list(APPEND TVM_RUNTIME_LINKER_LIBS ${CMAKE_DL_LIBS})
|
||||
endif()
|
||||
|
||||
# add source group
|
||||
tvm_file_glob(GLOB_RECURSE GROUP_SOURCE "src/*.cc")
|
||||
tvm_file_glob(GLOB_RECURSE GROUP_INCLUDE "src/*.h" "include/*.h")
|
||||
assign_source_group("Source" ${GROUP_SOURCE})
|
||||
assign_source_group("Include" ${GROUP_INCLUDE})
|
||||
|
||||
# Source file lists
|
||||
tvm_file_glob(GLOB_RECURSE COMPILER_SRCS
|
||||
src/ir/*.cc
|
||||
src/arith/*.cc
|
||||
src/te/*.cc
|
||||
src/tirx/*.cc
|
||||
src/s_tir/*.cc
|
||||
src/topi/*.cc
|
||||
src/driver/*.cc
|
||||
src/support/*.cc
|
||||
# TVMScript shared core (Doc IR + dispatch infrastructure + IR-layer
|
||||
# printer/builder). Per-dialect (relax, tirx, ...) printer/builder pieces
|
||||
# live under src/<dialect>/script/. The list below is intentionally explicit
|
||||
# (not src/script/*.cc) so that any new file accidentally added under
|
||||
# src/script/{printer,ir_builder}/<dialect>/ for a non-IR dialect is
|
||||
# rejected at link time rather than silently included.
|
||||
src/script/ir_builder/base.cc
|
||||
src/script/ir_builder/ir/*.cc
|
||||
src/script/printer/config.cc
|
||||
src/script/printer/script_printer.cc
|
||||
src/script/printer/doc.cc
|
||||
src/script/printer/doc_printer/*.cc
|
||||
src/script/printer/ir_docsifier.cc
|
||||
src/script/printer/ir/*.cc
|
||||
src/relax/ir/*.cc
|
||||
src/relax/op/*.cc
|
||||
src/relax/analysis/*.cc
|
||||
src/relax/transform/*.cc
|
||||
src/relax/backend/vm/*.cc
|
||||
src/relax/backend/adreno/*.cc
|
||||
src/relax/backend/task_extraction.cc
|
||||
src/relax/backend/pattern_registry.cc
|
||||
src/relax/utils.cc
|
||||
src/relax/distributed/*.cc
|
||||
src/relax/distributed/transform/*.cc
|
||||
src/relax/op/distributed/*.cc
|
||||
src/relax/script/*.cc
|
||||
src/relax/testing/*.cc
|
||||
)
|
||||
|
||||
tvm_file_glob(GLOB CODEGEN_SRCS
|
||||
src/target/*.cc
|
||||
src/target/source/*.cc
|
||||
src/target/canonicalizer/*.cc
|
||||
src/target/canonicalizer/llvm/*.cc
|
||||
src/backend/cuda/codegen/*.cc
|
||||
src/backend/cuda/op/*.cc
|
||||
src/backend/hexagon/codegen/*.cc
|
||||
src/backend/metal/codegen/*.cc
|
||||
src/backend/metal/op/*.cc
|
||||
src/backend/opencl/codegen/*.cc
|
||||
src/backend/rocm/codegen/*.cc
|
||||
src/backend/trn/codegen/*.cc
|
||||
src/backend/trn/op/*.cc
|
||||
src/backend/trn/transform/*.cc
|
||||
src/backend/vulkan/codegen/target_kind.cc
|
||||
src/backend/vulkan/codegen/vulkan_fallback_module.cc
|
||||
src/backend/webgpu/codegen/*.cc
|
||||
)
|
||||
|
||||
list(APPEND COMPILER_SRCS ${CODEGEN_SRCS})
|
||||
|
||||
tvm_file_glob(GLOB RUNTIME_SRCS
|
||||
src/runtime/*.cc
|
||||
src/runtime/vm/*.cc
|
||||
src/runtime/memory/*.cc
|
||||
src/runtime/rpc/minrpc/*.cc
|
||||
)
|
||||
# Note: src/runtime/extra/disco/** moves to libtvm_runtime_extra.
|
||||
# Note: src/backend/*/runtime sources move to per-backend DSOs.
|
||||
set(TVM_RUNTIME_EXT_OBJS "")
|
||||
|
||||
if(BUILD_FOR_HEXAGON)
|
||||
if(NOT BUILD_STATIC_RUNTIME)
|
||||
# Allow undefined symbols (there will be some from libc).
|
||||
set(TVM_NO_UNDEFINED_SYMBOLS "")
|
||||
endif()
|
||||
|
||||
add_definitions(-D_MACH_I32=int)
|
||||
endif()
|
||||
|
||||
# Package runtime rules
|
||||
if(NOT USE_RTTI)
|
||||
endif()
|
||||
|
||||
if(INDEX_DEFAULT_I64)
|
||||
add_definitions(-DTVM_INDEX_DEFAULT_I64=1)
|
||||
endif()
|
||||
|
||||
if(USE_RPC)
|
||||
message(STATUS "Build with RPC support...")
|
||||
tvm_file_glob(GLOB RUNTIME_RPC_SRCS src/runtime/rpc/*.cc)
|
||||
list(APPEND RUNTIME_SRCS ${RUNTIME_RPC_SRCS})
|
||||
endif(USE_RPC)
|
||||
# Note: disco/**, NCCL, NVSHMEM, RCCL all move to libtvm_runtime_extra
|
||||
# (assembled inline below after all contrib cmake files).
|
||||
|
||||
# Enable ctest if gtest is available
|
||||
if(USE_GTEST)
|
||||
# Check env var for backward compatibility. A better way to specify package
|
||||
# locations is to use CMAKE_PREFIX_PATH or other standard CMake mechanism
|
||||
# (see CMake documentation for `find_package`).
|
||||
set(GTEST_ROOT "$ENV{GTEST_LIB}")
|
||||
if("${USE_GTEST}" STREQUAL "AUTO")
|
||||
# If USE_GTEST is AUTO, treat GTest as optional: enable if found.
|
||||
find_package(GTest)
|
||||
elseif("${USE_GTEST}" MATCHES ${IS_TRUE_PATTERN})
|
||||
# USE_GTEST is set to ON, TRUE, etc. Treat GTest as a required package.
|
||||
find_package(GTest REQUIRED)
|
||||
endif()
|
||||
if(GTEST_FOUND)
|
||||
if(NOT TARGET GTest::gmock)
|
||||
# GMock is formally supported in CMake 3.20; for now, expect libgmock.a in the same directory,
|
||||
# and require that folks compiling against GTest::gmock also link against GTest::GTest
|
||||
# (for the includes dir).
|
||||
add_library(GTest::gmock STATIC IMPORTED GLOBAL)
|
||||
get_target_property(GTEST_LIB_PATH GTest::GTest IMPORTED_LOCATION)
|
||||
if("${GTEST_LIB_PATH}" STREQUAL "GTEST_LIB_PATH-NOTFOUND")
|
||||
# CMake >= 3.20 makes GTest::GTest into a compatibility target. The real import location is in
|
||||
# GTest::gtest.
|
||||
get_target_property(GTEST_LIB_PATH GTest::gtest IMPORTED_LOCATION)
|
||||
if("${GTEST_LIB_PATH}" STREQUAL "GTEST_LIB_PATH-NOTFOUND")
|
||||
message(FATAL_ERROR "Neither GTest::GTest nor GTest::gtest targets defined IMPORTED_LOCATION")
|
||||
endif()
|
||||
endif()
|
||||
get_filename_component(GTEST_LIB_DIR "${GTEST_LIB_PATH}" DIRECTORY)
|
||||
set_target_properties(GTest::gmock PROPERTIES
|
||||
IMPORTED_LOCATION "${GTEST_LIB_DIR}/libgmock.a")
|
||||
endif()
|
||||
|
||||
enable_testing()
|
||||
include(CTest)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(USE_KALLOC_ALIGNMENT)
|
||||
message(STATUS "Build Alloc alignment set to ${USE_KALLOC_ALIGNMENT}")
|
||||
add_definitions(-DTVM_KALLOC_ALIGNMENT=${USE_KALLOC_ALIGNMENT})
|
||||
endif(USE_KALLOC_ALIGNMENT)
|
||||
|
||||
# Caches the build.
|
||||
# Note that ccache-3.x doesn't support nvcc well, so CUDA kernels may never hit the cache and still
|
||||
# need to be re-compiled every time. Using ccache 4.0+ can resolve this issue.
|
||||
include(cmake/utils/CCache.cmake)
|
||||
|
||||
include(CheckCXXCompilerFlag)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
set(CMAKE_CUDA_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_CUDA_STANDARD 20)
|
||||
|
||||
# Module rules
|
||||
include(cmake/modules/CUDA.cmake)
|
||||
include(cmake/modules/Hexagon.cmake) # This must come before logging.cmake
|
||||
include(cmake/modules/contrib/CLML.cmake) # Must be before OpenCL.cmake
|
||||
include(cmake/modules/OpenCL.cmake)
|
||||
include(cmake/modules/OpenMP.cmake)
|
||||
include(cmake/modules/Vulkan.cmake)
|
||||
include(cmake/modules/Metal.cmake)
|
||||
include(cmake/modules/ROCM.cmake)
|
||||
include(cmake/modules/LLVM.cmake)
|
||||
include(cmake/modules/contrib/BLAS.cmake)
|
||||
include(cmake/modules/contrib/DNNL.cmake)
|
||||
include(cmake/modules/contrib/AMX.cmake)
|
||||
include(cmake/modules/contrib/CUTLASS.cmake)
|
||||
include(cmake/modules/contrib/Random.cmake)
|
||||
include(cmake/modules/contrib/Sort.cmake)
|
||||
include(cmake/modules/contrib/Z3.cmake)
|
||||
include(cmake/modules/contrib/CoreML.cmake)
|
||||
include(cmake/modules/contrib/TensorRT.cmake)
|
||||
include(cmake/modules/contrib/NNAPI.cmake)
|
||||
include(cmake/modules/contrib/ExampleNPU.cmake)
|
||||
include(cmake/modules/contrib/vllm.cmake)
|
||||
include(cmake/modules/Git.cmake)
|
||||
|
||||
# ---- libtvm_runtime_extra assembly ----
|
||||
# Disco core sources.
|
||||
tvm_file_glob(GLOB _disco_core_srcs src/runtime/extra/disco/*.cc)
|
||||
add_library(tvm_disco_objs OBJECT ${_disco_core_srcs})
|
||||
target_link_libraries(tvm_disco_objs PRIVATE tvm_runtime_extra_defs)
|
||||
target_link_libraries(tvm_runtime_extra PRIVATE tvm_disco_objs)
|
||||
|
||||
# Distributed disco (disabled for Hexagon cross-compile).
|
||||
if(NOT BUILD_FOR_HEXAGON)
|
||||
tvm_file_glob(GLOB _disco_dist_srcs src/runtime/extra/disco/distributed/*.cc)
|
||||
add_library(tvm_disco_distributed_objs OBJECT ${_disco_dist_srcs})
|
||||
target_link_libraries(tvm_disco_distributed_objs PRIVATE tvm_runtime_extra_defs)
|
||||
target_link_libraries(tvm_runtime_extra PRIVATE tvm_disco_distributed_objs)
|
||||
endif()
|
||||
|
||||
# NCCL / cuda_ipc — requires CUDA + NCCL.
|
||||
if(USE_CUDA AND USE_NCCL)
|
||||
find_nccl(${USE_NCCL})
|
||||
include_directories(SYSTEM ${NCCL_INCLUDE_DIR})
|
||||
tvm_file_glob(GLOB _nccl_srcs src/runtime/extra/disco/nccl/*.cc src/runtime/extra/disco/cuda_ipc/*.cc 3rdparty/tensorrt_llm/*.cu)
|
||||
set_source_files_properties(src/runtime/extra/disco/nccl/nccl.cc PROPERTIES COMPILE_DEFINITIONS "TVM_NCCL_RCCL_SWITCH=0")
|
||||
add_library(tvm_nccl_objs OBJECT ${_nccl_srcs})
|
||||
target_link_libraries(tvm_nccl_objs PRIVATE tvm_runtime_extra_defs)
|
||||
find_library(LIBRT rt)
|
||||
target_link_libraries(tvm_runtime_extra PRIVATE tvm_nccl_objs nccl ${LIBRT})
|
||||
endif()
|
||||
|
||||
# NVSHMEM.
|
||||
if(USE_CUDA AND USE_NVSHMEM)
|
||||
find_nvshmem(${USE_NVSHMEM})
|
||||
if(NOT NVSHMEM_FOUND)
|
||||
message(FATAL_ERROR "Cannot find NVSHMEM, USE_NVSHMEM=" ${USE_NVSHMEM})
|
||||
endif()
|
||||
set(CMAKE_CUDA_SEPARABLE_COMPILATION ON)
|
||||
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||
tvm_file_glob(GLOB _nvshmem_srcs src/runtime/extra/contrib/nvshmem/*.cc src/runtime/extra/contrib/nvshmem/*.cu)
|
||||
add_library(tvm_nvshmem_objs OBJECT ${_nvshmem_srcs})
|
||||
target_link_libraries(tvm_nvshmem_objs PRIVATE tvm_runtime_extra_defs)
|
||||
target_include_directories(tvm_nvshmem_objs PUBLIC ${NVSHMEM_INCLUDE_DIR})
|
||||
find_library(NVSHMEM_HOST nvshmem_host ${NVSHMEM_LIB_DIR})
|
||||
find_library(NVSHMEM_DEVICE nvshmem_device ${NVSHMEM_LIB_DIR})
|
||||
target_link_libraries(tvm_runtime_extra PRIVATE tvm_nvshmem_objs ${NVSHMEM_HOST} ${NVSHMEM_DEVICE})
|
||||
set_target_properties(tvm_runtime_extra PROPERTIES CUDA_SEPARABLE_COMPILATION ON)
|
||||
endif()
|
||||
|
||||
# RCCL.
|
||||
if(USE_ROCM AND USE_RCCL)
|
||||
find_rccl(${USE_RCCL})
|
||||
include_directories(SYSTEM ${RCCL_INCLUDE_DIR})
|
||||
tvm_file_glob(GLOB _rccl_srcs src/runtime/extra/disco/nccl/*.cc)
|
||||
set_source_files_properties(src/runtime/extra/disco/nccl/nccl.cc PROPERTIES COMPILE_DEFINITIONS "TVM_NCCL_RCCL_SWITCH=1")
|
||||
add_library(tvm_rccl_objs OBJECT ${_rccl_srcs})
|
||||
target_link_libraries(tvm_rccl_objs PRIVATE tvm_runtime_extra_defs)
|
||||
target_link_libraries(tvm_runtime_extra PRIVATE tvm_rccl_objs rccl)
|
||||
endif()
|
||||
|
||||
target_link_libraries(tvm_runtime_extra PUBLIC tvm_runtime)
|
||||
|
||||
# If disco/cuda_ipc is included, link the CUDA DSO.
|
||||
if(USE_CUDA)
|
||||
target_link_libraries(tvm_runtime_extra PUBLIC tvm_runtime_cuda)
|
||||
endif()
|
||||
|
||||
# CUTLASS fpA_intB_gemm and flash_attn are separate shared libs.
|
||||
if(USE_CUDA AND USE_CUTLASS)
|
||||
target_link_libraries(tvm_runtime_extra PRIVATE fpA_intB_gemm fpA_intB_gemm_tvm)
|
||||
target_link_libraries(tvm_runtime_extra PRIVATE -Wl,--no-as-needed flash_attn)
|
||||
endif()
|
||||
|
||||
if(TVM_VISIBILITY_FLAG)
|
||||
set_property(TARGET tvm_runtime_extra APPEND PROPERTY LINK_OPTIONS "${TVM_VISIBILITY_FLAG}")
|
||||
endif()
|
||||
|
||||
tvm_configure_target_library(tvm_runtime_extra RUNTIME_MODULE)
|
||||
|
||||
add_library(tvm_objs OBJECT ${COMPILER_SRCS})
|
||||
add_library(tvm_runtime_objs OBJECT ${RUNTIME_SRCS})
|
||||
target_link_libraries(tvm_objs PUBLIC tvm_ffi_header)
|
||||
target_link_libraries(tvm_runtime_objs PUBLIC tvm_ffi_header)
|
||||
if(TARGET tvm_llvm_header)
|
||||
target_link_libraries(tvm_objs PUBLIC tvm_llvm_header)
|
||||
endif()
|
||||
|
||||
include(GNUInstallDirs)
|
||||
|
||||
# Runtime library: built from runtime sources only. Loaded with RTLD_GLOBAL on
|
||||
# Linux/macOS so its symbols are exposed to downstream loads (e.g. NVRTC kernels
|
||||
# and other dynamically loaded modules that resolve runtime symbols at link
|
||||
# time).
|
||||
if(BUILD_STATIC_RUNTIME)
|
||||
add_library(tvm_runtime STATIC
|
||||
$<TARGET_OBJECTS:tvm_runtime_objs>
|
||||
${TVM_RUNTIME_EXT_OBJS}
|
||||
)
|
||||
set(NOTICE_MULTILINE
|
||||
"You have build static version of the TVM runtime library. Make "
|
||||
"sure to use --whole-archive when linking it into your project.")
|
||||
string(CONCAT NOTICE ${NOTICE_MULTILINE})
|
||||
add_custom_command(TARGET tvm_runtime POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E cmake_echo_color --yellow --bold ${NOTICE})
|
||||
target_link_libraries(tvm_runtime PUBLIC tvm_ffi_static)
|
||||
else()
|
||||
add_library(tvm_runtime SHARED
|
||||
$<TARGET_OBJECTS:tvm_runtime_objs>
|
||||
${TVM_RUNTIME_EXT_OBJS}
|
||||
)
|
||||
set_property(TARGET tvm_runtime APPEND PROPERTY LINK_OPTIONS "${TVM_NO_UNDEFINED_SYMBOLS}")
|
||||
target_link_libraries(tvm_runtime PUBLIC tvm_ffi_shared)
|
||||
endif()
|
||||
|
||||
target_include_directories(tvm_runtime PUBLIC "$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>")
|
||||
set_property(TARGET tvm_runtime APPEND PROPERTY LINK_OPTIONS "${TVM_VISIBILITY_FLAG}")
|
||||
# ``-fvisibility=hidden`` only affects symbol export when applied at COMPILE
|
||||
# time. Setting it as a link option (above) is preserved for back-compat but
|
||||
# is effectively a no-op for visibility — the per-TU compile flag is what
|
||||
# actually hides symbols. Apply it to the OBJECT libs that feed both shared
|
||||
# libraries.
|
||||
if(TVM_VISIBILITY_FLAG)
|
||||
target_compile_options(tvm_runtime_objs PRIVATE "${TVM_VISIBILITY_FLAG}")
|
||||
target_compile_options(tvm_objs PRIVATE "${TVM_VISIBILITY_FLAG}")
|
||||
endif()
|
||||
|
||||
# Compiler library: built from compiler-only sources.
|
||||
# Links against tvm_runtime (and tvm_ffi_shared transitively). Loaded with
|
||||
# RTLD_LOCAL so compiler-internal symbols don't leak into the global namespace.
|
||||
add_library(tvm_compiler SHARED
|
||||
$<TARGET_OBJECTS:tvm_objs>
|
||||
)
|
||||
target_link_libraries(tvm_compiler PUBLIC tvm_runtime tvm_ffi_shared)
|
||||
target_include_directories(tvm_compiler PUBLIC "$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>")
|
||||
set_property(TARGET tvm_compiler APPEND PROPERTY LINK_OPTIONS "${TVM_NO_UNDEFINED_SYMBOLS}")
|
||||
set_property(TARGET tvm_compiler APPEND PROPERTY LINK_OPTIONS "${TVM_VISIBILITY_FLAG}")
|
||||
|
||||
# Work around a GNU ld (binutils) relaxation bug that miscompiles
|
||||
# R_X86_64_GOTPCRELX relocations inside very large statically-linked archives.
|
||||
# When the full LLVM static libraries are linked into libtvm_compiler.so, the
|
||||
# library is large enough that ld can relax an indirect GOT call (LLVM built
|
||||
# with -fno-plt emits these) into a direct call with an incorrect displacement.
|
||||
# The call then targets read-only data instead of the intended function and
|
||||
# crashes at runtime with a SIGSEGV inside llvm::X86Subtarget during code
|
||||
# generation. Disabling linker relaxation keeps the GOT-indirect sequences and
|
||||
# avoids the miscompilation; it is harmless when LLVM is linked dynamically.
|
||||
# See binutils bug ld/25754.
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "Linux" AND NOT "${USE_LLVM}" MATCHES ${IS_FALSE_PATTERN})
|
||||
set_property(TARGET tvm_compiler APPEND PROPERTY LINK_OPTIONS "-Wl,--no-relax")
|
||||
# LLVM's --system-libs reports -lxml2, but TVM calls no libxml2 symbols. The
|
||||
# manylinux toolchain does not default to --as-needed, so set it explicitly:
|
||||
# the unused libxml2 is then not recorded as a NEEDED dependency, so auditwheel
|
||||
# does not vendor it (and its deps) into the wheel.
|
||||
set_property(TARGET tvm_compiler APPEND PROPERTY LINK_OPTIONS "-Wl,--as-needed")
|
||||
endif()
|
||||
|
||||
# Place runtime/compiler/allvisible artifacts under build/lib/ to mirror the
|
||||
# tvm-ffi layout and make tvm_ffi.libinfo.load_lib_ctypes(package="tvm") able
|
||||
# to discover them in dev / editable builds.
|
||||
set_target_properties(tvm_runtime PROPERTIES
|
||||
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
|
||||
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
|
||||
)
|
||||
set_target_properties(tvm_compiler PROPERTIES
|
||||
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
|
||||
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
|
||||
)
|
||||
if(MSVC)
|
||||
foreach(config_type Release RELEASE Debug DEBUG RelWithDebInfo RELWITHDEBINFO MinSizeRel MINSIZEREL)
|
||||
set_target_properties(tvm_runtime PROPERTIES
|
||||
ARCHIVE_OUTPUT_DIRECTORY_${config_type} "${CMAKE_BINARY_DIR}/lib"
|
||||
LIBRARY_OUTPUT_DIRECTORY_${config_type} "${CMAKE_BINARY_DIR}/lib"
|
||||
RUNTIME_OUTPUT_DIRECTORY_${config_type} "${CMAKE_BINARY_DIR}/lib"
|
||||
)
|
||||
set_target_properties(tvm_compiler PROPERTIES
|
||||
ARCHIVE_OUTPUT_DIRECTORY_${config_type} "${CMAKE_BINARY_DIR}/lib"
|
||||
LIBRARY_OUTPUT_DIRECTORY_${config_type} "${CMAKE_BINARY_DIR}/lib"
|
||||
RUNTIME_OUTPUT_DIRECTORY_${config_type} "${CMAKE_BINARY_DIR}/lib"
|
||||
)
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
|
||||
# logging option for libbacktrace
|
||||
include(cmake/modules/Logging.cmake)
|
||||
|
||||
if(USE_CPP_RPC)
|
||||
add_subdirectory("apps/cpp_rpc")
|
||||
endif()
|
||||
|
||||
if(USE_CPP_RTVM)
|
||||
add_subdirectory("apps/cpp_rtvm")
|
||||
endif()
|
||||
|
||||
if(USE_IOS_RPC)
|
||||
add_subdirectory("apps/ios_rpc")
|
||||
endif()
|
||||
|
||||
add_subdirectory(3rdparty/tvm-ffi)
|
||||
|
||||
if(TVM_DEBUG_WITH_ABI_CHANGE)
|
||||
message(STATUS "Building with debug code that may cause ABI changes...")
|
||||
target_compile_definitions(tvm_objs PRIVATE "TVM_DEBUG_WITH_ABI_CHANGE")
|
||||
target_compile_definitions(tvm_runtime_objs PRIVATE "TVM_DEBUG_WITH_ABI_CHANGE")
|
||||
endif(TVM_DEBUG_WITH_ABI_CHANGE)
|
||||
|
||||
if(USE_THREADS AND NOT BUILD_FOR_HEXAGON)
|
||||
message(STATUS "Build with thread support...")
|
||||
set(CMAKE_THREAD_PREFER_PTHREAD TRUE)
|
||||
set(THREADS_PREFER_PTHREAD_FLAG TRUE)
|
||||
find_package(Threads REQUIRED)
|
||||
target_link_libraries(tvm_compiler PUBLIC Threads::Threads)
|
||||
target_link_libraries(tvm_runtime PUBLIC Threads::Threads)
|
||||
endif()
|
||||
|
||||
target_link_libraries(tvm_compiler PRIVATE ${TVM_LINKER_LIBS})
|
||||
|
||||
target_link_libraries(tvm_compiler PRIVATE ${TVM_RUNTIME_LINKER_LIBS})
|
||||
target_link_libraries(tvm_runtime PRIVATE ${TVM_RUNTIME_LINKER_LIBS})
|
||||
|
||||
# Set flags for clang
|
||||
include(cmake/modules/ClangFlags.cmake)
|
||||
set(TVM_TEST_LIBRARY_NAME tvm_compiler)
|
||||
|
||||
# Create the `cpptest` target if we can find GTest. If not, we create dummy
|
||||
# targets that give the user an informative error message.
|
||||
if(GTEST_FOUND)
|
||||
tvm_file_glob(GLOB_RECURSE TEST_SRCS tests/cpp/*.cc)
|
||||
add_executable(cpptest ${TEST_SRCS})
|
||||
# include runtime files for unit testing
|
||||
target_link_libraries(cpptest PRIVATE ${TVM_TEST_LIBRARY_NAME} GTest::GTest GTest::Main GTest::gmock pthread dl)
|
||||
if(DEFINED LLVM_LIBS)
|
||||
# The TVM library is linked with LLVM libraries. If the LLVM libraries are
|
||||
# static and the symbols are not hidden, then don't link them again into
|
||||
# cpptest since cpptest is itself linked against the TVM library. If static
|
||||
# LLVM libraries are linked in twice, it can cause issues with global
|
||||
# variable initialization (cl::opt).
|
||||
# If the LLVM libraries are dynamic, we have to link them again, since the
|
||||
# TVM library will not contain any LLVM definitions.
|
||||
unset(LLVM_SO)
|
||||
foreach(L IN LISTS LLVM_LIBS)
|
||||
if(L MATCHES "libLLVM.*\.so")
|
||||
set(LLVM_SO TRUE)
|
||||
break()
|
||||
endif()
|
||||
endforeach()
|
||||
if(DEFINED LLVM_SO OR HIDE_PRIVATE_SYMBOLS)
|
||||
target_link_libraries(cpptest PRIVATE ${LLVM_LIBS})
|
||||
endif()
|
||||
endif()
|
||||
set_target_properties(cpptest PROPERTIES EXCLUDE_FROM_ALL 1)
|
||||
set_target_properties(cpptest PROPERTIES EXCLUDE_FROM_DEFAULT_BUILD 1)
|
||||
# cpptest is built into ${CMAKE_BINARY_DIR} but the TVM shared libs it
|
||||
# links against (libtvm_compiler.so / libtvm_runtime.so) now live in
|
||||
# ${CMAKE_BINARY_DIR}/lib. CMake's default behaviour bakes the
|
||||
# absolute path of build/lib/ into the binary's RUNPATH, which works in tree
|
||||
# but is not relocatable. Set $ORIGIN/lib (or @loader_path/lib on macOS)
|
||||
# explicitly so the test binary finds its TVM libs relative to its own
|
||||
# location, mirroring the install-time RPATH setup.
|
||||
if(APPLE)
|
||||
set_target_properties(cpptest PROPERTIES
|
||||
BUILD_RPATH "@loader_path/lib"
|
||||
INSTALL_RPATH "@loader_path/lib"
|
||||
)
|
||||
elseif(UNIX)
|
||||
set_target_properties(cpptest PROPERTIES
|
||||
BUILD_RPATH "\$ORIGIN/lib"
|
||||
INSTALL_RPATH "\$ORIGIN/lib"
|
||||
)
|
||||
endif()
|
||||
target_compile_definitions(cpptest PRIVATE "NDEBUG")
|
||||
if(TVM_DEBUG_WITH_ABI_CHANGE)
|
||||
target_compile_definitions(cpptest PRIVATE "TVM_DEBUG_WITH_ABI_CHANGE")
|
||||
endif(TVM_DEBUG_WITH_ABI_CHANGE)
|
||||
|
||||
# For some reason, compile definitions are not propagated correctly, so we manually add them here
|
||||
target_compile_definitions(cpptest PUBLIC $<TARGET_PROPERTY:tvm_compiler,INTERFACE_COMPILE_DEFINITIONS>)
|
||||
gtest_discover_tests(cpptest)
|
||||
endif()
|
||||
|
||||
# Custom targets
|
||||
add_custom_target(runtime DEPENDS tvm_runtime)
|
||||
|
||||
# Installation rules
|
||||
install(TARGETS tvm_compiler DESTINATION lib${LIB_SUFFIX})
|
||||
install(TARGETS tvm_runtime DESTINATION lib${LIB_SUFFIX})
|
||||
|
||||
if (INSTALL_DEV)
|
||||
install(
|
||||
DIRECTORY "include/" DESTINATION "include"
|
||||
FILES_MATCHING
|
||||
PATTERN "*.h"
|
||||
)
|
||||
else(INSTALL_DEV)
|
||||
install(
|
||||
DIRECTORY "include/tvm/runtime/" DESTINATION "include/tvm/runtime"
|
||||
FILES_MATCHING
|
||||
PATTERN "*.h"
|
||||
)
|
||||
endif(INSTALL_DEV)
|
||||
|
||||
include(CMakePackageConfigHelpers)
|
||||
set(PROJECT_CONFIG_CONTENT "@PACKAGE_INIT@\n")
|
||||
string(APPEND PROJECT_CONFIG_CONTENT "include(CMakeFindDependencyMacro)\n")
|
||||
string(APPEND PROJECT_CONFIG_CONTENT "find_dependency(Threads REQUIRED)\n")
|
||||
string(APPEND PROJECT_CONFIG_CONTENT
|
||||
"include(\"\${CMAKE_CURRENT_LIST_DIR}/${PROJECT_NAME}Targets.cmake\")")
|
||||
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/temp_config_file.cmake" ${PROJECT_CONFIG_CONTENT})
|
||||
|
||||
# install(EXPORT ${PROJECT_NAME}Targets
|
||||
# NAMESPACE ${PROJECT_NAME}::
|
||||
# DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME})
|
||||
|
||||
# Create config for find_package()
|
||||
configure_package_config_file(
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/temp_config_file.cmake" ${PROJECT_NAME}Config.cmake
|
||||
INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}")
|
||||
|
||||
install(
|
||||
FILES
|
||||
"${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.cmake"
|
||||
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}")
|
||||
|
||||
# More target definitions
|
||||
if(MSVC)
|
||||
# tvm_objs builds libtvm_compiler.dll → TVM_DLL=dllexport,
|
||||
# but TVM_RUNTIME_DLL=dllimport (runtime symbols come from libtvm_runtime.dll).
|
||||
target_compile_definitions(tvm_objs PRIVATE -DTVM_EXPORTS -DTVM_FFI_EXPORTS)
|
||||
# tvm_runtime_objs builds libtvm_runtime.dll → TVM_RUNTIME_DLL=dllexport.
|
||||
# No TVM_EXPORTS here: the runtime side never defines compiler-exported
|
||||
# symbols, so leaving TVM_DLL as dllimport correctly fails any accidental
|
||||
# use of compiler-side ``TVM_DLL`` symbols from a runtime TU.
|
||||
target_compile_definitions(tvm_runtime_objs PRIVATE -DTVM_RUNTIME_EXPORTS -DTVM_FFI_EXPORTS)
|
||||
endif()
|
||||
|
||||
set(TVM_IS_DEBUG_BUILD OFF)
|
||||
if(CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo" OR CMAKE_CXX_FLAGS MATCHES "-g")
|
||||
set(TVM_IS_DEBUG_BUILD ON)
|
||||
endif()
|
||||
|
||||
# Change relative paths in backtrace to absolute ones
|
||||
if(TVM_IS_DEBUG_BUILD)
|
||||
set(FILE_PREFIX_MAP_FLAG "-ffile-prefix-map=..=${CMAKE_CURRENT_SOURCE_DIR}")
|
||||
target_compile_options(tvm_compiler PRIVATE "${FILE_PREFIX_MAP_FLAG}")
|
||||
CHECK_CXX_COMPILER_FLAG("${FILE_PREFIX_MAP_FLAG}" FILE_PREFIX_MAP_SUPPORTED)
|
||||
if(FILE_PREFIX_MAP_SUPPORTED)
|
||||
target_compile_options(tvm_compiler PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${FILE_PREFIX_MAP_FLAG}>)
|
||||
target_compile_options(tvm_objs PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${FILE_PREFIX_MAP_FLAG}>)
|
||||
target_compile_options(tvm_runtime PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${FILE_PREFIX_MAP_FLAG}>)
|
||||
target_compile_options(tvm_runtime_objs PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${FILE_PREFIX_MAP_FLAG}>)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
tvm_ffi_add_apple_dsymutil(tvm_compiler)
|
||||
# Only run dsymutil on shared libraries, not static libraries
|
||||
if(NOT BUILD_STATIC_RUNTIME)
|
||||
tvm_ffi_add_apple_dsymutil(tvm_runtime)
|
||||
endif()
|
||||
|
||||
if(BUILD_FOR_HEXAGON)
|
||||
# Wrap pthread_create to allow setting custom stack size.
|
||||
set_property(TARGET tvm_runtime APPEND PROPERTY LINK_FLAGS
|
||||
"-Wl,--wrap=pthread_create")
|
||||
# Link tvm_runtime into the RPC skel library. Make sure it's built
|
||||
# as a part of the "runtime" target.
|
||||
if(USE_HEXAGON_RPC)
|
||||
target_link_libraries(
|
||||
hexagon_rpc_skel -Wl,--whole-archive tvm_runtime tvm_ffi_static -Wl,--no-whole-archive)
|
||||
add_dependencies(runtime hexagon_rpc_skel)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
find_and_set_linker(${USE_ALTERNATIVE_LINKER})
|
||||
|
||||
if(${SUMMARIZE})
|
||||
print_summary()
|
||||
endif()
|
||||
|
||||
dump_options_to_file("${TVM_ALL_OPTIONS}")
|
||||
|
||||
if(USE_CUDA AND USE_CUTLASS)
|
||||
install(TARGETS fpA_intB_gemm EXPORT ${PROJECT_NAME}Targets DESTINATION lib${LIB_SUFFIX})
|
||||
install(TARGETS flash_attn EXPORT ${PROJECT_NAME}Targets DESTINATION lib${LIB_SUFFIX})
|
||||
# fpA_intB_gemm, fpA_intB_gemm_tvm, and flash_attn are linked by
|
||||
# tvm_runtime_extra (see the inline assembly block above); no link needed here.
|
||||
endif()
|
||||
|
||||
if(USE_CUDA AND USE_NVTX)
|
||||
add_compile_definitions(TVM_NVTX_ENABLED=1)
|
||||
endif()
|
||||
|
||||
# Note: NCCL, NVSHMEM, RCCL target_link_libraries are handled in the inline
|
||||
# libtvm_runtime_extra assembly block above.
|
||||
|
||||
# Keep the core shared libraries relocatable. A relative rpath
|
||||
# ($ORIGIN / @loader_path) is correct in any build because the sibling runtime
|
||||
# DSOs are installed next to each other, so apply it unconditionally rather than
|
||||
# only when building the Python wheel. (tvm_runtime_extra already gets its rpath
|
||||
# where it is defined above.)
|
||||
tvm_configure_target_library(tvm_compiler)
|
||||
tvm_configure_target_library(tvm_runtime)
|
||||
|
||||
# Python package installation configuration
|
||||
# This section ensures that all necessary files are installed for the Python wheel
|
||||
if(TVM_BUILD_PYTHON_MODULE)
|
||||
message(STATUS "Configuring Python package installation")
|
||||
|
||||
# Install compiled shared libraries into <project>/lib so that
|
||||
# tvm_ffi.libinfo.load_lib_ctypes(package="tvm", target_name=...) can find
|
||||
# them via the package RECORD or the project's lib/ fallback dir.
|
||||
install(TARGETS tvm_compiler DESTINATION "lib")
|
||||
install(TARGETS tvm_runtime DESTINATION "lib")
|
||||
|
||||
# Install third-party compiled dependencies into the same lib/ dir.
|
||||
if(TARGET fpA_intB_gemm)
|
||||
tvm_configure_target_library(fpA_intB_gemm)
|
||||
install(TARGETS fpA_intB_gemm DESTINATION "lib")
|
||||
endif()
|
||||
if(TARGET flash_attn)
|
||||
tvm_configure_target_library(flash_attn)
|
||||
install(TARGETS flash_attn DESTINATION "lib")
|
||||
endif()
|
||||
|
||||
# Install prebuilt extra runtime libraries into the same lib/ dir. This is how
|
||||
# the separately-built CUDA runtime (libtvm_runtime_cuda.so) is bundled: the
|
||||
# publishing flow builds it in a CUDA-enabled environment and passes its path
|
||||
# via TVM_PACKAGE_EXTRA_LIBS, so it ships through the normal CMake install
|
||||
# rather than a post-build wheel rewrite.
|
||||
foreach(_extra_lib IN LISTS TVM_PACKAGE_EXTRA_LIBS)
|
||||
if(NOT EXISTS "${_extra_lib}")
|
||||
message(FATAL_ERROR "TVM_PACKAGE_EXTRA_LIBS entry does not exist: ${_extra_lib}")
|
||||
endif()
|
||||
install(FILES "${_extra_lib}" DESTINATION "lib")
|
||||
endforeach()
|
||||
|
||||
# Install minimal header files needed by Python extensions
|
||||
install(
|
||||
DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/include/tvm/runtime/"
|
||||
DESTINATION "include/tvm/runtime/"
|
||||
FILES_MATCHING
|
||||
PATTERN "*.h"
|
||||
)
|
||||
|
||||
# Install minimal CMake configuration
|
||||
install(
|
||||
DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/cmake/utils/"
|
||||
DESTINATION "cmake/utils/"
|
||||
FILES_MATCHING
|
||||
PATTERN "*.cmake"
|
||||
)
|
||||
|
||||
# Install CUTLASS headers only if available
|
||||
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/cutlass/include")
|
||||
install(
|
||||
DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/cutlass/include/"
|
||||
DESTINATION "3rdparty/cutlass/include/"
|
||||
FILES_MATCHING
|
||||
PATTERN "*.h"
|
||||
PATTERN "*.hpp"
|
||||
)
|
||||
endif()
|
||||
|
||||
# Install minimal source files
|
||||
install(
|
||||
DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/src/runtime/"
|
||||
DESTINATION "src/runtime/"
|
||||
FILES_MATCHING
|
||||
PATTERN "*.cc"
|
||||
PATTERN "*.h"
|
||||
)
|
||||
|
||||
# Install web package
|
||||
install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/web/" DESTINATION "web/")
|
||||
|
||||
# Install licenses (required for distribution)
|
||||
install(
|
||||
DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/licenses/"
|
||||
DESTINATION "licenses/"
|
||||
)
|
||||
|
||||
# Install essential metadata files
|
||||
install(FILES
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/README.md"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/LICENSE"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/NOTICE"
|
||||
DESTINATION "."
|
||||
)
|
||||
|
||||
message(STATUS "Python package installation configured")
|
||||
endif()
|
||||
+243
@@ -0,0 +1,243 @@
|
||||
<!--- Licensed to the Apache Software Foundation (ASF) under one -->
|
||||
<!--- or more contributor license agreements. See the NOTICE file -->
|
||||
<!--- distributed with this work for additional information -->
|
||||
<!--- regarding copyright ownership. The ASF licenses this file -->
|
||||
<!--- to you under the Apache License, Version 2.0 (the -->
|
||||
<!--- "License"); you may not use this file except in compliance -->
|
||||
<!--- with the License. You may obtain a copy of the License at -->
|
||||
|
||||
<!--- http://www.apache.org/licenses/LICENSE-2.0 -->
|
||||
|
||||
<!--- Unless required by applicable law or agreed to in writing, -->
|
||||
<!--- software distributed under the License is distributed on an -->
|
||||
<!--- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -->
|
||||
<!--- KIND, either express or implied. See the License for the -->
|
||||
<!--- specific language governing permissions and limitations -->
|
||||
<!--- under the License. -->
|
||||
|
||||
TVM Contributors
|
||||
================
|
||||
TVM adopts the Apache way and governs by merit. We believe that it is important to create an inclusive community where everyone can use,
|
||||
contribute to, and influence the direction of the project. We actively invite contributors who have earned the merit to be part of the development community.
|
||||
|
||||
See the [community structure document](https://tvm.apache.org/docs/contribute/community.html) for the explanation of community structure and contribution guidelines.
|
||||
|
||||
|
||||
## Committers
|
||||
|
||||
We add tag along with committer name to show areas that they are familiar with.
|
||||
We do encourage everyone to work anything they are interested in.
|
||||
|
||||
- [Aditya Atluri](https://github.com/adityaatluri): @adityaatluri - rocm
|
||||
- [Matthew Barrett](https://github.com/mbaret): @mbaret - byoc, arm
|
||||
- [Matthew Brookhart](https://github.com/mbrookhart): @mbrookhart - relay, frontends
|
||||
- [Yaxing Cai](https://github.com/cyx-6): @cyx-6 - tvm-script, runtime
|
||||
- [Liangfu Chen](https://github.com/liangfu): @liangfu - vta, chisel, intel FPGA, c runtime
|
||||
- [Tianqi Chen](https://github.com/tqchen) (PMC): @tqchen - topi, compiler, relay, docs
|
||||
- [Wei Chen](https://github.com/wweic): @wweic - runtime, relay, vm
|
||||
- [Zhi Chen](https://github.com/zhiics) (PMC): @zhiics - relay, quantization, pass manager
|
||||
- [Egor Churaev](https://github.com/echuraev): @echuraev - metal, opencl, adreno
|
||||
- [Balint Cristian](https://github.com/cbalint13): @cbalint13
|
||||
- [Siyuan Feng](https://github.com/Hzfengsy) (PMC): @Hzfengsy - tir
|
||||
- [Josh Fromm](https://github.com/jwfromm) (PMC): @jwfromm - frontends, quantization, topi
|
||||
- [Mehrdad Hessar](https://github.com/mehrdadh): @mehrdadh - microTVM, hexagon
|
||||
- [Masahiro Hiramori](https://github.com/mshr-h): @mshr-h - relax, frontend
|
||||
- [Bohan Hou](https://github.com/spectrometerHBH) (PMC): @spectrometerHBH - tir, arith, tvm-script
|
||||
- [Yuwei Hu](https://github.com/Huyuwei): @Huyuwei - topi, frontends
|
||||
- [Luke Hutton](https://github.com/lhutton1): @lhutton1 - ethos-u, arm
|
||||
- [Nick Hynes](https://github.com/nhynes): @nhynes: - sgx, rust
|
||||
- [Animesh Jain](https://github.com/anijain2305): @anijain2305 - quantization, relay
|
||||
- [Chenfan Jia](https://github.com/jcf94): @jcf94 - auto_scheduler
|
||||
- [Ziheng Jiang](https://github.com/ZihengJiang) (PMC): @ZihengJiang - relay, compiler
|
||||
- [Hongyi Jin](https://github.com/jinhongyii): @jinhongyii - tir, tvm-script, arith, relay, topi
|
||||
- [Manupa Karunaratne](https://github.com/manupak): @manupak - ethos-u, memory planner
|
||||
- [Elen Kalda](https://github.com/ekalda): @ekalda - ethos-u, arm
|
||||
- [Marisa Kirisame](https://github.com/MarisaKirisame): @MarisaKirisame - relay
|
||||
- [Tristan Konolige](https://github.com/tkonolige): @tkonolige - profiling, relay, tir, runtime
|
||||
- [Ruihang Lai](https://github.com/MasterJH5574) (PMC): @MasterJH5574 - tir, tvm-script
|
||||
- [Wuwei Lin](https://github.com/vinx13) (PMC): @vinx13 - relay, topi, tir, meta_schedule
|
||||
- [Yizhi Liu](https://github.com/yzhliu) (PMC): @yzhliu - jvm, topi, relay
|
||||
- [Hao Lu](https://github.com/hlu1): @hlu1 - nnpack, frontends
|
||||
- [Eric Lunderberg](https://github.com/Lunderberg): @Lunderberg - CI, Vulkan backend
|
||||
- [Andrew Z. Luo](https://github.com/AndrewZhaoLuo): @AndrewZhaoLuo - amp, relay, frontends
|
||||
- [Steven Lyubomirsky](https://github.com/slyubomirsky): @slyubomirsky - relay
|
||||
- [Masahiro Masuda](https://github.com/masahi) (PMC): @masahi - topi, relay
|
||||
- [Thierry Moreau](https://github.com/tmoreau89) (PMC): @tmoreau89 - vta
|
||||
- [Kazutaka Morita](https://github.com/kazum): @kazum - frontends, opencl
|
||||
- [Trevor Morris](https://github.com/trevor-m): @trevor-m - byoc, compiler
|
||||
- [Leandro Nunes](https://github.com/leandron) (PMC): @leandron - tvmc
|
||||
- [Lily Orth-Smith](https://github.com/electriclilies): @electriclilies - relay
|
||||
- [Ashutosh Parkhi](https://github.com/ashutosh-arm): @ashutosh-arm - cmsis-nn
|
||||
- [Krzysztof Parzyszek](https://github.com/kparzysz-quic) (PMC): @kparzysz-quic - hexagon, llvm
|
||||
- [Andrew Reusch](https://github.com/areusch): (PMC) @areusch - runtime, microTVM
|
||||
- [David Riazati](https://github.com/driazati): @driazati - ci, community
|
||||
- [Jared Roesch](https://github.com/jroesch) (PMC): @jroesch - relay
|
||||
- [Gustavo Romero](https://github.com/gromero): @gromero - microtvm, tvmc
|
||||
- [Giuseppe Rossini](https://github.com/giuseros): @giuseros - aot, arm
|
||||
- [Siju Samuel](https://github.com/siju-samuel): @siju-samuel - frontends
|
||||
- [Christopher Sidebottom](https://github.com/Mousius): @Mousius - arm, ethos-u, relay
|
||||
- [Junru Shao](https://github.com/junrushao) (PMC): @junrushao - relay, compiler
|
||||
- [Haichen Shen](https://github.com/icemelon) (PMC): @icemelon - relay, topi
|
||||
- [Chris Sullivan](https://github.com/csullivan): @csullivan - amd backend
|
||||
- [Siva Rama Krishna Reddy](https://github.com/srkreddy1238): @srkreddy1238 - frontends, golang
|
||||
- [Zhixun Tan](https://github.com/phisiart): @phisiart - opengl, web
|
||||
- [Tong Meng](https://github.com/Archermmt): @Archermmt - msc
|
||||
- [Andrew Tulloch](https://github.com/ajtulloch): @ajtulloch - topi, compiler, runtime
|
||||
- [Gavin Uberti](https://github.com/guberti): @guberti - microtvm, arm
|
||||
- [Luis Vega](https://github.com/vegaluisjose): @vegaluisjose - vta, chisel
|
||||
- [Leyuan Wang](https://github.com/Laurawly) (PMC): @Laurawly: - topi
|
||||
- [Yao Wang](https://github.com/kevinthesun): @kevinthesun (PMC): - topi, vision
|
||||
- [Jian Weng](https://github.com/were): @were: - hybrid script
|
||||
- [Zhao Wu](https://github.com/FrozenGene): @FrozenGene - runtime, topi, frontends
|
||||
- [Eddie Yan](https://github.com/eqy) (PMC): @eqy - runtime, autotvm, rpc, topi
|
||||
- [Zihao Ye](https://github.com/yzh119): @yzh119 - tir
|
||||
- [Hao Yu](https://github.com/comaniac): @comaniac (PMC) - relay, byoc, auto_scheduler
|
||||
- [Shuai Yuan](https://github.com/ysh329): @ysh329 (PMC) - ci
|
||||
- [Qiang Zhang](https://github.com/Johnson9009): @Johnson9009 - relay, tvm-script
|
||||
- [Lianmin Zheng](https://github.com/merrymercy) (PMC): @merrymercy - autotvm, auto_scheduler, topi, relay
|
||||
- [Xiyou Zhou](https://github.com/zxybazh): @zxybazh - relay
|
||||
- [wrongtest](https://github.com/wrongtest-intellif) (PMC): @wrongtest-intellif - tir, tvm-script, arith
|
||||
- [Anirudh Sundar Subramaniam](https://github.com/quic-sanirudh): @quic-sanirudh
|
||||
|
||||
## Reviewers
|
||||
|
||||
- [Aditya Atluri](https://github.com/adityaatluri): @adityaatluri
|
||||
- [Matthew Barrett](https://github.com/mbaret): @mbaret
|
||||
- [Arnaud Bergeron](https://github.com/abergeron): @abergeron
|
||||
- [Florin Blanaru](https://github.com/gigiblender): @gigiblender
|
||||
- [Matthew Brookhart](https://github.com/mbrookhart): @mbrookhart
|
||||
- [Yaxing Cai](https://github.com/cyx-6): @cyx-6
|
||||
- [Liangfu Chen](https://github.com/liangfu): @liangfu
|
||||
- [Tianqi Chen](https://github.com/tqchen): @tqchen
|
||||
- [Zhi Chen](https://github.com/zhiics): @zhiics
|
||||
- [Valery Chernov](https://github.com/vvchernov): @vvchernov
|
||||
- [Neo Chien](https://github.com/cchung100m): @cchung100m
|
||||
- [Christian Convey](https://github.com/cconvey/): @cconvey
|
||||
- [Meghan Cowan](https://github.com/cowanmeg): @cowanmeg
|
||||
- [Balint Cristian](https://github.com/cbalint13): @cbalint13
|
||||
- [Egor Churaev](https://github.com/echuraev): @echuraev
|
||||
- [Xiaoqiang Dan](https://github.com/xqdan): @xqdan
|
||||
- [Yixin Dong](https://github.com/Ubospica) @Ubospica
|
||||
- [Haozheng Fan](https://github.com/hzfan): @hzfan
|
||||
- [Siyuan Feng](https://github.com/Hzfengsy): @Hzfengsy
|
||||
- [Josh Fromm](https://github.com/jwfromm): @jwfromm
|
||||
- [Alexey Gladyshev](https://github.com/KJlaccHoeUM9l): @KJlaccHoeUM9l
|
||||
- [Sergei Grechanik](https://github.com/sgrechanik-h): @sgrechanik-h
|
||||
- [Altan Haan](https://github.com/altanh): @altanh
|
||||
- [Mehrdad Hessar](https://github.com/mehrdadh): @mehrdadh
|
||||
- [Masahiro Hiramori](https://github.com/mshr-h): @mshr-h
|
||||
- [Bohan Hou](https://github.com/spectrometerHBH): @spectrometerHBH
|
||||
- [Yuwei Hu](https://github.com/Huyuwei): @Huyuwei
|
||||
- [Luke Hutton](https://github.com/lhutton1): @lhutton1
|
||||
- [Nick Hynes](https://github.com/nhynes): @nhynes
|
||||
- [Animesh Jain](https://github.com/anijain2305): @anijain2305
|
||||
- [Chenfan Jia](https://github.com/jcf94): @jcf94
|
||||
- [Hua Jiang](https://github.com/huajsj): @huajsj
|
||||
- [Ziheng Jiang](https://github.com/ZihengJiang): @ZihengJiang
|
||||
- [Hongyi Jin](https://github.com/jinhongyii): @jinhongyii
|
||||
- [Manupa Karunaratne](https://github.com/manupak): @manupak
|
||||
- [Elen Kalda](https://github.com/ekalda): @ekalda
|
||||
- [Marisa Kirisame](https://github.com/MarisaKirisame): @MarisaKirisame
|
||||
- [Michael J. Klaiber](https://github.com/MichaelJKlaiber/) @MichaelJKlaiber
|
||||
- [Noah Kontur](https://github.com/konturn/) @konturn
|
||||
- [Tristan Konolige](https://github.com/tkonolige): @tkonolige
|
||||
- [Mohamad Katanbaf](https://github.com/mkatanbaf): @mkatanbaf
|
||||
- [Denise Kutnick](https://github.com/denise-k): @denise-k
|
||||
- [Ruihang Lai](https://github.com/MasterJH5574): @MasterJH5574
|
||||
- [Nicola Lancellotti](https://github.com/nicolalancellotti): @NicolaLancellotti
|
||||
- [Wuwei Lin](https://github.com/vinx13): @vinx13
|
||||
- [Andrew Liu](https://github.com/hypercubestart): @hypercubestart
|
||||
- [Henry Liu](https://github.com/optima2005): @optima2005
|
||||
- [Xin Liu](https://github.com/Meteorix): @Meteorix
|
||||
- [Yizhi Liu](https://github.com/yzhliu) : @yzhliu
|
||||
- [Hao Lu](https://github.com/hlu1): @hlu1
|
||||
- [Eric Lunderberg](https://github.com/Lunderberg): @Lunderberg
|
||||
- [Andrew Z. Luo](https://github.com/AndrewZhaoLuo): @AndrewZhaoLuo
|
||||
- [Steven Lyubomirsky](https://github.com/slyubomirsky): @slyubomirsky
|
||||
- [Alan MacDonald](https://github.com/alanmacd): @alanmacd
|
||||
- [Masahiro Masuda](https://github.com/masahi): @masahi
|
||||
- [Andrey Malyshev](https://github.com/elvin-n): @elvin-n
|
||||
- [Sergey Mironov](https://github.com/grwlf): @grwlf
|
||||
- [Thierry Moreau](https://github.com/tmoreau89): @tmoreau89
|
||||
- [Kazutaka Morita](https://github.com/kazum): @kazum
|
||||
- [Trevor Morris](https://github.com/trevor-m): @trevor-m
|
||||
- [Tatsuya Nishiyama](https://github.com/nishi-t): @nishi-t
|
||||
- [Leandro Nunes](https://github.com/leandron): @leandron
|
||||
- [Jiawei Liu](https://github.com/ganler): @ganler
|
||||
- [Lily Orth-Smith](https://github.com/electriclilies): @electriclilies
|
||||
- [Wei Pan](https://github.com/wpan11nv): @wpan11nv
|
||||
- [Michalis Papadimitriou](https://github.com/mikepapadim): @mikepapadim
|
||||
- [Krzysztof Parzyszek](https://github.com/kparzysz-quic): @kparzysz-quic
|
||||
- [Sunghyun Park](https://github.com/sunggg): @sunggg
|
||||
- [Ashutosh Parkhi](https://github.com/ashutosh-arm): @ashutosh-arm
|
||||
- [Alexander Peskov](https://github.com/apeskov): @apeskov
|
||||
- [Pariksheet Pinjari](https://github.com/PariksheetPinjari909): @PariksheetPinjari909
|
||||
- [Josh Pollock](https://github.com/joshpoll): @joshpoll
|
||||
- [Ramana Radhakrishnan](https://github.com/u99127): @u99127
|
||||
- [Andrew Reusch](https://github.com/areusch): @areusch
|
||||
- [David Riazati](https://github.com/driazati): @driazati
|
||||
- [Jared Roesch](https://github.com/jroesch): @jroesch
|
||||
- [Gustavo Romero](https://github.com/gromero): @gromero
|
||||
- [Giuseppe Rossini](https://github.com/giuseros): @giuseros
|
||||
- [Siju Samuel](https://github.com/siju-samuel): @siju-samuel
|
||||
- [Janet Schneider](https://github.com/janetsc): @janetsc
|
||||
- [Junru Shao](https://github.com/junrushao): @junrushao
|
||||
- [Haichen Shen](https://github.com/icemelon): @icemelon
|
||||
- [Qingchao Shen](https://github.com/jikechao): @jikechao
|
||||
- [Xingjian Shi](https://github.com/sxjscience): @sxjscience
|
||||
- [Yuanjing Shi](https://github.com/shingjan): @shingjan
|
||||
- [Mark Shields](https://github.com/mbs-octoml): @mbs-octoml
|
||||
- [Christopher Sidebottom](https://github.com/mousius): @mousius
|
||||
- [Siva Rama Krishna Reddy](https://github.com/srkreddy1238): @srkreddy1238
|
||||
- [Dmitriy Smirnov](https://github.com/d-smirnov): @d-smirnov
|
||||
- [Jon Soifer](https://github.com/soiferj): @soiferj
|
||||
- [Adam Straw](https://github.com/adstraw): @adstraw
|
||||
- [Chris Sullivan](https://github.com/csullivan): @csullivan
|
||||
- [Anirudh Sundar Subramaniam](https://github.com/quic-sanirudh): @quic-sanirudh
|
||||
- [Zhixun Tan](https://github.com/phisiart): @phisiart
|
||||
- [Tong Meng](https://github.com/Archermmt): @Archermmt
|
||||
- [Andrew Tulloch](https://github.com/ajtulloch): @ajtulloch
|
||||
- [Jorn Tuyls](https://github.com/jtuyls): @jtuyls
|
||||
- [Gavin Uberti](https://github.com/guberti): @guberti
|
||||
- [Luis Vega](https://github.com/vegaluisjose): @vegaluisjose
|
||||
- [Jyotsna Verma](https://github.com/jverma-quic): @jverma-quic
|
||||
- [Thomas Viehmann](https://github.com/t-vi): @t-vi
|
||||
- [An Wang](https://github.com/anwang2009): @anwang2009
|
||||
- [Yao Wang](https://github.com/kevinthesun): @kevinthesun
|
||||
- [Yuchen Wang](https://github.com/wyc-ruiker): @wyc-ruiker
|
||||
- [Leyuan Wang](https://github.com/Laurawly): @Laurawly
|
||||
- [Alex Weaver](https://github.com/alex-weaver): @alex-weaver
|
||||
- [Logan Weber](https://github.com/weberlo): @weberlo
|
||||
- [Matt Welsh](https://github.com/mdw-octoml): @mdw-octoml
|
||||
- [Cheng Wen](https://github.com/chengven027-intellif): @chengven027-intellif
|
||||
- [Jian Weng](https://github.com/were): @were
|
||||
- [wrongtest](https://github.com/wrongtest-intellif): @wrongtest-intellif
|
||||
- [Yong Wu](https://github.com/yongwww): @yongwww
|
||||
- [Zhao Wu](https://github.com/FrozenGene): @FrozenGene
|
||||
- [Bing Xu](https://github.com/antinucleon): @antinucleon
|
||||
- [Eddie Yan](https://github.com/eqy): @eqy
|
||||
- [Aleksei Yazev](https://github.com/Aleksei-grovety): @Aleksei-grovety
|
||||
- [Zihao Ye](https://github.com/yzh119): @yzh119
|
||||
- [Hao Yu](https://github.com/comaniac): @comaniac
|
||||
- [Shuai Yuan](https://github.com/ysh329): @ysh329
|
||||
- [Joshua Z. Zhang](https://github.com/zhreshold): @zhreshold
|
||||
- [Lianmin Zheng](https://github.com/merrymercy): @merrymercy
|
||||
- [Min Chen](https://github.com/multiverstack-intellif): @multiverstack-intellif
|
||||
- [Xiyou Zhou](https://github.com/zxybazh): @zxybazh
|
||||
- [@blackkker](https://github.com/blackkker): @blackkker
|
||||
- [Jiajun Jiang](https://github.com/jiangjiajun): @jiangjiajun
|
||||
- [Qiang Zhang](https://github.com/Johnson9009): @Johnson9009
|
||||
|
||||
## List of Contributors
|
||||
- [Full List of Contributors](https://github.com/apache/tvm/graphs/contributors)
|
||||
|
||||
## Mentors
|
||||
|
||||
TVM is now a top-level Apache project. During our Incubator phase, we were fortunate to have the following mentors.
|
||||
|
||||
- Markus Weimer @markusweimer
|
||||
- Sebastian Schelter @sscdotopen
|
||||
- Byung-Gon Chun @bgchun
|
||||
- Henry Saputra @hsaputra
|
||||
- Timothy Chen @tnachen
|
||||
- Furkan KAMACI @kamaci
|
||||
@@ -0,0 +1,762 @@
|
||||
This file contains the PGP keys of various developers.
|
||||
Please don't use them for email unless you have to. Their main
|
||||
purpose is code signing.
|
||||
|
||||
Examples of importing this file in your keystore:
|
||||
gpg --import KEYS.txt
|
||||
(need pgp and other examples here)
|
||||
|
||||
Examples of adding your key to this file:
|
||||
pgp -kxa <your name> and append it to this file.
|
||||
(pgpk -ll <your name> && pgpk -xa <your name>) >> this file.
|
||||
(gpg --list-sigs <your name>
|
||||
&& gpg --armor --export <your name>) >> this file.
|
||||
|
||||
-----------------------------------------------------------------------------------
|
||||
pub rsa4096 2019-11-15 [SC]
|
||||
EF52D68AD5276994249816836754EA97C55E3DEB
|
||||
uid [ultimate] Tianqi Chen (CODE SIGNING KEY) <tqchen@apache.org>
|
||||
sig 3 6754EA97C55E3DEB 2019-11-15 Tianqi Chen (CODE SIGNING KEY) <tqchen@apache.org>
|
||||
sub rsa4096 2019-11-15 [E]
|
||||
sig 6754EA97C55E3DEB 2019-11-15 Tianqi Chen (CODE SIGNING KEY) <tqchen@apache.org>
|
||||
|
||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
|
||||
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
|
||||
ha8fS9ysWDy/Ye65MP4=
|
||||
=MSiP
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
||||
pub rsa4096 2018-02-07 [SC]
|
||||
F42C1A6E634C105E8D985105CA751254E97B9FE4
|
||||
uid [ultimate] Yizhi Liu <liuyizhi@apache.org>
|
||||
sig 3 CA751254E97B9FE4 2018-02-07 Yizhi Liu <liuyizhi@apache.org>
|
||||
sub rsa4096 2018-02-07 [E]
|
||||
sig CA751254E97B9FE4 2018-02-07 Yizhi Liu <liuyizhi@apache.org>
|
||||
|
||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
|
||||
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
|
||||
=1xfH
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
||||
pub rsa4096 2020-09-24 [SC]
|
||||
6A0D4938D8C052C759AE2460ED03B26E4FC3509F
|
||||
uid [ultimate] Ziheng Jiang <ziheng@apache.org>
|
||||
sig 3 ED03B26E4FC3509F 2020-09-24 Ziheng Jiang <ziheng@apache.org>
|
||||
sub rsa4096 2020-09-24 [E]
|
||||
sig ED03B26E4FC3509F 2020-09-24 Ziheng Jiang <ziheng@apache.org>
|
||||
|
||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
|
||||
mQINBF9tEiUBEAC90om00alNSupM78ZZYMdwKZnJLIhAD22YARntVNVBuD9Znpuo
|
||||
BAYwjrWdAi/npwN+r+Pd7Oz6fMBCmB3e4tsrPnBzauGb6aKgjBMHcVEx0p1197kk
|
||||
WcGuKt4FNlHYfmc2sOOQre2GcIVOU1XuK8tAhgca78aorAlMtOqq+/ASnKcjRSjW
|
||||
0AOzlEKfaGVgst2UO7Fc/w59S3/qv1vBGKnlqLvsJU7kNR1gFotqsGAee5Vu7alQ
|
||||
WiHFJbW9ujLTPu7m8enFVuBGFkPsW89Yl/0mXnAKZFFNCHIQ9gkT+1bvZhx8ViJL
|
||||
4UeqG7wnSLSSIQz2UPBJYV5stxNtd9HS08Tfviv37shd1SSprFLoQDk87j7wF60b
|
||||
AR5IjbVgdprpmVNncO5pnyZwXXWVi7ZyiMSaW6wg+lkeQMGflxgL+05xOafJYgO6
|
||||
UepXqu1mc7Q4eVUyft/EPmdyvlg7Fo4T4Db2PnstonkZCyLogdaaJRuxCc0AR/O1
|
||||
oNaodrdjqydXVnP3d/gJ5gj78zeMPVbGbzwhpIwhfDouxftaU5zc6prBsMgY/os6
|
||||
XMe9bNZWpOLXZrmo/ovaiebmxT5ZYuFRGdeRl1/Y5CWE6Q9JM8euwKuskNQ4G0aY
|
||||
fVQ61Cxg4hmrnsv9YFAjf9PPWhpFHvILQoGSs3HbJCLFPphKf37gzfiZMQARAQAB
|
||||
tCBaaWhlbmcgSmlhbmcgPHppaGVuZ0BhcGFjaGUub3JnPokCTgQTAQgAOBYhBGoN
|
||||
STjYwFLHWa4kYO0Dsm5Pw1CfBQJfbRIlAhsDBQsJCAcCBhUKCQgLAgQWAgMBAh4B
|
||||
AheAAAoJEO0Dsm5Pw1CfBl0P/R04MxtqC4aI0fpdwmed55kGunL1W65phBgcOrDL
|
||||
58cv5dKJzUmfSUXw3QANcFSn9Q9Z2clj+a2aiGKV5cUiWN0Ny7y6wd3aVOXlRHHy
|
||||
f30aDO5Ug5RDYbcChTpen+kq9qDXSr/NxXYLWvhobMeXfiA9Priv49fFWEr17Kai
|
||||
NOuoix/eWA5WpnPMf/Rz4HibKcX/izXTW0NOH54jn+4P9M4ZwWbn0AXKoq2i3zF2
|
||||
vZavCStcscrfs+kihtEVvwUkyrmSIblIUdkPNxeo/jx7N9Fbu2zXbhl5JiBmBUMJ
|
||||
XyFUOBSUDUzA5EvWwXp0yatULOoCH/LIyt+lLdkyfDjsKmAavGf9CcFHVyDIG95N
|
||||
34/jECPwwVVkbauE0XYOwenOh+Be1goOA6nidB4QT/rGns7zvCNG8+3ttwA4aiE5
|
||||
3GrVWXiPaEMaoM56Phscek30GoLjB2gjvwgwa9oGTDYTu8Z4ifLk8qq8ij9uEG7V
|
||||
cKns+1C3ZvfdKi8SmOzj/v9krOi8N4YW03YS2Oq/cGPD/SttoMTOCPxi0PLR7uqy
|
||||
YXugsebxlJlXBNTeZx+iiKmkrsILjEd8pUChw79crtH2SGOPqIv1BsqObstLV04r
|
||||
iiywruqLRIGlsr8BtepCeEfzW9nJRw7W2571t7oD7QbkdCJ4WUyhMJH73+7KFEE2
|
||||
fKL5uQINBF9tEiUBEACmMcP8/zm88BmyhDjWV3ZrZ9cn0N3JJfSONt0AcyE5TZ2y
|
||||
20DnHkp3/lNK6EC0k7twtcce/cnKDbXQ/IpuJZwReq5SgmCoGbBZShjALtVCzQRm
|
||||
pSA6Wl0JBfw36/IdKUuf8LZtENqp3jgQkkT3TA+/bCh1KQLDYFoVQjUBLiWCDHiL
|
||||
iBV5L/PH97l93hkxbSDXrBemQRbr+xhA2TzwcmrjnscNCAXkwU9f1Ygh8zDHSJKB
|
||||
g7Ln+ot6QsPhNQEQWhju5xfAn9+kO8OWSAZF/lJTT2Wy+spDBP1ZnviQadWPj5HL
|
||||
n4G1qe4QWl08E9FtqVKC7r1YYzT4DlTU2AQ0bJqdvAtojX9ji2Hp4ov8xYPHzy3a
|
||||
ZRdDYNWN6i0mbpzj8SYojyEG5cy2j+nzGOYTEdpwW8pG2aCwRvnO+UqXNM3UyQk3
|
||||
9Tyfyzw6m9mlq9zaw/nfvOIA6Ns2QR5+UbplkpwVMqMAzZNyEV2wPe9B195MN6tq
|
||||
KcznzawD/W1ORccOxrpBXhN3sJSc5n8Uy5pHUHg9B/TdCSLpr7tqqS34gB+AcSUL
|
||||
NxjdLn72JHKxCp/wpg3Z4bmY5n/bh/D7Ovt7LP1D/MW9wiR3ls/PtNAK4+SV6oqt
|
||||
G1MNS0QgAitovF8dpmX+/zPKax7baZiJY/sDr9crfRvd6e+HYA3yDo08Z44MTwAR
|
||||
AQABiQI2BBgBCAAgFiEEag1JONjAUsdZriRg7QOybk/DUJ8FAl9tEiUCGwwACgkQ
|
||||
7QOybk/DUJ9Txw/+NXL6cKEIm4NQrBc0RmX37sELc5UnvpycV663OiPF9qHE9iML
|
||||
EUt/LBxrGUarplOA66EIkmmnekUgS8ujjhGOw152nSuZTgoPxX4ub6PI7Hi5lmqI
|
||||
ZtEpp8VoI+XxAdA5ecN5QNP7P/ovSIZwXvIF00YXqGp6keXi/qdYkylt4s6zLDiL
|
||||
ocfOZWt994JVIl30gogkw4PmcWx+PKXos+Hq1La7iZUn1pT5kEsN+fHpnh42sAGZ
|
||||
dhb+puB5tczhVJhL553Z6rh4BABd1DqAZihwelkRRvQUp0Fqgc2oxty5o5pdHZdS
|
||||
ulomOqGgERHsrtwzqD/n3iep3z22LiitZHsKZ0OoHl9e1YsvdsL5rImEz/FdWwgl
|
||||
muO2ZjY2KhuovFROCsGVgw3b9gzIjtE8FWE6wSz6qzKihBbI8YPtQqGJgnX2A01m
|
||||
AkfpGPb8430OghDCQFsrWkuTjmSw42ys1lALbK2yQGRuOCq0dIml1QdE6JfU8ceW
|
||||
QY1dhH7xpHQxlr9Tcv+enCc4UzCJOnXgkVUnD/u+TqKL9GoSFu6KQrC7jyvfY9t8
|
||||
Elf2ReXYVK/jGUePdDFurp+3KFlAHFuen2VZTcNZaUWoYoI84VDEh8/oPEPfzveJ
|
||||
/GhL5vbglB0H0aG8SVMaTfzr+nXHUVyOSrlYYk34O7bSimVrX6XDGPZpsXE=
|
||||
=nhJ/
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
||||
pub 4096R/D75EFD4B 2020-09-24
|
||||
uid Zhi Chen <zhic@apache.org>
|
||||
sig 3 D75EFD4B 2020-09-24 Zhi Chen <zhic@apache.org>
|
||||
sub 4096R/285DD7CB 2020-09-24
|
||||
sig D75EFD4B 2020-09-24 Zhi Chen <zhic@apache.org>
|
||||
|
||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
|
||||
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
|
||||
=GEwA
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
||||
pub rsa4096 2021-11-10 [SC]
|
||||
C5E5C09030E7BD32DF9A67CE35ABC9676004ADAE
|
||||
uid [ultimate] Junru Shao <junrushao@apache.org>
|
||||
sig 3 35ABC9676004ADAE 2021-11-10 Junru Shao <junrushao@apache.org>
|
||||
sub rsa4096 2021-11-10 [E]
|
||||
sig 35ABC9676004ADAE 2021-11-10 Junru Shao <junrushao@apache.org>
|
||||
|
||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
|
||||
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
|
||||
=jNCy
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
||||
pub rsa4096 2021-11-10 [SC]
|
||||
43C2306EBED3D533F2CFBA8A2C75E5A496C80880
|
||||
uid [ultimate] Wuwei Lin <wuwei@apache.org>
|
||||
sig 3 2C75E5A496C80880 2021-11-10 Wuwei Lin <wuwei@apache.org>
|
||||
sub rsa4096 2021-11-10 [E]
|
||||
sig 2C75E5A496C80880 2021-11-10 Wuwei Lin <wuwei@apache.org>
|
||||
|
||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
|
||||
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
|
||||
=+gLd
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
||||
pub rsa3072 2022-07-12 [SC] [expires: 2024-07-11]
|
||||
B3C6A14C13B8C6727BC2FD2F07FA463F1C926F48
|
||||
uid [ultimate] David Riazati <driazati@apache.org>
|
||||
sig 3 07FA463F1C926F48 2022-07-12 David Riazati <driazati@apache.org>
|
||||
sub rsa3072 2022-07-12 [E] [expires: 2024-07-11]
|
||||
sig 07FA463F1C926F48 2022-07-12 David Riazati <driazati@apache.org>
|
||||
|
||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
|
||||
mQGNBGLNzqUBDAC9p7OMYiiVHTQIIUr1/fDXaJ3sJ0rlkaPQJpPBrtuqGjN5utDu
|
||||
26BWQqPxx36aABw44UmTRwV4UNf+3McYSJoCODfVpHOKsKk0Ql5CDzG3Ngpdu9ZR
|
||||
UxV6s2DNHkSUjpd5vRfZF09WnQ0WITEhKz8Wnm82B/NkvRmTzYqlpP+zOT3+WPFh
|
||||
5maMPOP0bvEfiT22zQqOOyKraYPrtf5ZBSip1fYohOlyS/aJcqOChMuKMOBVrxqH
|
||||
9EmHjEkN0a+nAdWnGmCoGZONsD4ifXL17AUOaGSpEko6Nj7nXyTKI0laBhj6f8uw
|
||||
v8M3xDBkIm7oiTuwrCeDa4e9YtP6Vzvj6MxrpNIMN0XRs/DRYH0lgTI1Zv/0SzkO
|
||||
OAa9tOCiq95jkMjZik/vyQ55WwkMgYDmngsP/PBEW2ztdVLoLeal2p4HNfBM1BQO
|
||||
RFOGnurR2Vmy1jGPyfpuBNMyjRgFC43s7SLiTYKCi1QxyY5u6dRgjIxkG+jyiY3B
|
||||
GFMAtPt5iJHUox0AEQEAAbQjRGF2aWQgUmlhemF0aSA8ZHJpYXphdGlAYXBhY2hl
|
||||
Lm9yZz6JAdQEEwEKAD4WIQSzxqFME7jGcnvC/S8H+kY/HJJvSAUCYs3OpQIbAwUJ
|
||||
A8JnAAULCQgHAgYVCgkICwIEFgIDAQIeAQIXgAAKCRAH+kY/HJJvSJHEC/wMgDH/
|
||||
jBI6AciNp9sPv2p8tFRDywq2nUOameYFaIMq1r644IAzUUU3PSACMT1lCxGjFFsE
|
||||
vJYx1GORrpqjwArrK1D3zZ0yb4X38DFAU+7DTGEKzKoz3h+Ka0GyOe90CI/KqqWL
|
||||
XNeePwvOzIWhZ0U8vqUkgXwHyfG1dwocEx5A1zlTeznkth2AnRELnjhFcj28V2VX
|
||||
dUQmZ8qOYxXtjSk9xJtQ/BbARiNINeKqzG1aPWgjTtFFp3UTl/jWCr5RBlWMA+BU
|
||||
N9alE/ozRPx89Uilz2reaC7xX8tHv5F+P7SPVwMhJyYQ7F577CtM0b4vTu4U15wE
|
||||
VlWF25ymTbSt5kam9jFbeR0Zkc0/LuLEdGWRGbDFI9Hj1rGeBejTm+PjwK3TidDn
|
||||
KbvpUgvseNfqUQPcbjEsuwYVUtR/LEeQxt2tK/odQwWlHR7BQApFhV7VSJVP99Fp
|
||||
YNFN7AsiD7+k4fOl5Qeq/t6X7x+gXMkxsRvtJMwB/fTAWbuBxdQBdIkP/KC5AY0E
|
||||
Ys3OpQEMALhC8woP92ONpgRKHhH3s65cY4EYLhfhkbOqU8KcbPJX0qx1gM68jWqm
|
||||
aCvez9KO+aB2jEyWG65XsOJXM6RqFtgvFMKG+ETLIgPydqt9l4f5AhnrPXmrxf7l
|
||||
b8unuFMyoga7DyKnB6hQzEVqZgbKR+U6lWaoFtGTFYlaOdUz268OErrW3592frh0
|
||||
VKTdCyBdGPfiwKnzL4+LjU7SuiI9r1nBH5ZYicGmgOKQHP0KQRUy66Cq0S7p0rpp
|
||||
9owbh2FHkXJ0bryl7AMV5JurEk0FSA483qQjyqHEQCSKVySgUBBFw9UPH0LkUbYv
|
||||
jk43VFoUYexlJ47KFIRJdQZdLyyqsSy0xzqiCQXFwQPECIFHN/GTMuAHcaCfah/z
|
||||
u4KDkqArzNzG1pl/DYVuaMo9LmBtzB7kfxPKcvm0atp6WHydcQ92N9ZU9z2zBh7T
|
||||
u6Akzl+eONsix7F0oldwtG7Glic+1HafyyjhZfV8o6r7rYURnsotDfdzYjpL/xWe
|
||||
xWkUSv2GbwARAQABiQG8BBgBCgAmFiEEs8ahTBO4xnJ7wv0vB/pGPxySb0gFAmLN
|
||||
zqUCGwwFCQPCZwAACgkQB/pGPxySb0g+0wv+MQO/9mVo4eblTeFMLpLlU1tbDXIF
|
||||
n5bDxbd1ekq/fKLrWZpT+MQGprGMXbgTehgeBIMvFvANLr2KHUb4HpXTX1GceVHv
|
||||
A5uN/JQ+/H+IF3SoipcFPDR67uESVSZQfrky6HG8M9hH4OPdW4LbyEBke13Z2LlK
|
||||
sQWJFznDnqCqmvLDvvliGBGhMM3RvTn5upgA47gwcJ1Z4xZU+k1nyhAiAgxGxpjO
|
||||
rtj/Dv7r7gdnDBo5omu0fQLqulSY1UeHsOQXlkR6zMOMDdKgybcScQHQhta0Hcs+
|
||||
DWxpfJ92vH/3wGchSA1f0Fp2WCiQ/wp7sfe1esShDN12AwlpDBjK583d0R+DLpVY
|
||||
8DbRCdvtwIN2f5KD+LhBbBX66AADVKVRIPgGDRGxc85X06nVWOQGHrGD+tCjxBNM
|
||||
aLLvg9K8HxeWTvQvowCAyFJo4NfIrS/7gMm5JcWMAqVFJ+IVxZNxZUIYV0VBC/AN
|
||||
rSSBN90DWxIgPhlAqgO0ofkbPSVwF/9i7nd3
|
||||
=XBuV
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
||||
pub rsa4096 2022-10-10 [SC]
|
||||
1B63BD2FFF5E515DA1BEF393C9A56ABD5CCA3EB8
|
||||
uid [ultimate] Andrew Zhao Luo <andrewzhaoluo@apache.org>
|
||||
sig 3 C9A56ABD5CCA3EB8 2022-10-10 Andrew Zhao Luo <andrewzhaoluo@apache.org>
|
||||
sub rsa4096 2022-10-10 [E]
|
||||
sig C9A56ABD5CCA3EB8 2022-10-10 Andrew Zhao Luo <andrewzhaoluo@apache.org>
|
||||
|
||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
|
||||
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
|
||||
/lFRrVmO
|
||||
=rAtV
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
||||
|
||||
pub rsa4096 2023-02-02 [SC]
|
||||
466390C69A21ABAE77DC63F128D4862222B8EC31
|
||||
uid [ultimate] Leandro Nunes <leandron@apache.org>
|
||||
sig 3 28D4862222B8EC31 2023-02-02 Leandro Nunes <leandron@apache.org>
|
||||
sub rsa4096 2023-02-02 [E]
|
||||
sig 28D4862222B8EC31 2023-02-02 Leandro Nunes <leandron@apache.org>
|
||||
|
||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
|
||||
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
|
||||
tO0=
|
||||
=PI53
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
||||
pub rsa4096 2023-05-05 [SC]
|
||||
664EF29634C05669C3DCF83106D051CA84EF3749
|
||||
uid [ultimate] Siyuan Feng (CODE SIGNING KEY) <syfeng@apache.org>
|
||||
sig 3 06D051CA84EF3749 2023-05-05 Siyuan Feng (CODE SIGNING KEY) <syfeng@apache.org>
|
||||
sub rsa4096 2023-05-05 [E]
|
||||
sig 06D051CA84EF3749 2023-05-05 Siyuan Feng (CODE SIGNING KEY) <syfeng@apache.org>
|
||||
|
||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
|
||||
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
|
||||
wS/UuN04NxDy7V6mPXE=
|
||||
=MTba
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
||||
pub rsa4096 2024-01-15 [SC]
|
||||
A4D9228E55761E665BF01CBB5CE869CB7DEC048C
|
||||
uid [ultimate] Star Yuan (CODE SIGNING KEY) <ysh329@apache.org>
|
||||
sig 3 5CE869CB7DEC048C 2024-01-15 Star Yuan (CODE SIGNING KEY) <ysh329@apache.org>
|
||||
sub rsa4096 2024-01-15 [E]
|
||||
sig 5CE869CB7DEC048C 2024-01-15 Star Yuan (CODE SIGNING KEY) <ysh329@apache.org>
|
||||
|
||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
|
||||
mQINBGWlStcBEADaslyfbUNARhWftJoRAChoak0cFU6NxahhvyZfyTGtSuwuHNDD
|
||||
2eyvhnDIaYXVClxoNgikiQ5Nkd1jtbA4rFCw6Pdbq+98fkpcr8N4o+jlbpu6Ff3j
|
||||
dJ2Qu000MV5qe9FZ4QasdfglJElvizgfNbJv/Fz1ERl/BS1U0c7lyQF9jGGh7EY2
|
||||
1y+JFp5OMG6A9SpfaOd+iOw5/cfCQk8+sHQC4dp3hOJPK4NLvjotK+hlOhRsF7gU
|
||||
goYYT2IP56kPQb6U/Uiv4/R6HbKugzqSMl6BMwAb9uG6UX0xUfAA8ciHoaITCJCQ
|
||||
9e/jGWnDnqYlAMNqLkHEmW7THxJ3hHXcac/Z1C3PeLDJU0rpTxDcjuYkM5jFCu7H
|
||||
TgT7lWBP/PyAAVSsLqMQbLJOWm0a14tb/oRoeYr/B2prIbJY5qJBM1nherKGMg0G
|
||||
7Oqugo6A1VqgUxg7Chj73PledaNwvm5Lxpl6D+wPDSifhlz0vnwOCMoOon0pTjK4
|
||||
DXDEXnEXZtzkZgXI6g7AkVyt0gkqyUi+01ibmlBfcVHh3PVvU4oNdkaywQd5s29R
|
||||
DsA4WOqt9cLv+iqIzM1juygfR6ooA1jHDIyIPmmC/kOrcxKXEFvIGXDDCbXAvdXc
|
||||
uXgZeZqI3pbKjQaU3fF8HwJ956HTM8rywtVGH9BWRl/i6qn5sq9CcukcuQARAQAB
|
||||
tDBTdGFyIFl1YW4gKENPREUgU0lHTklORyBLRVkpIDx5c2gzMjlAYXBhY2hlLm9y
|
||||
Zz6JAk4EEwEKADgWIQSk2SKOVXYeZlvwHLtc6GnLfewEjAUCZaVK1wIbAwULCQgH
|
||||
AgYVCgkICwIEFgIDAQIeAQIXgAAKCRBc6GnLfewEjBAiD/0cfaYfQ0DL7CPsP0lS
|
||||
yezPDDTnDPIo//G1cuSYG0gnXQ1SpbJSzDE7deew+P506/sWFneOY5Kuv6DuSE8J
|
||||
nM6vv1EYR4/9x/XstA4F04lQPngKKBV+UKrWj8zIA2Drn345Ece1150bWvrUD7mT
|
||||
+ps1gfe8SGYpOmR/kRc8qra2zizcWBC1Dl4qd+RcY7Ac6Cu3G/JG2KvZnrUSVev9
|
||||
nzSl2V0JtFVIla2odSJqv0Zdj5E2vLvQd3Dxbf3BODCdL3iQqxrQhj+0T3QLEhPg
|
||||
y2XOtqW7a96XosoQ44wUiHaS5LwFViG8LoiPADtSdXYb8m4FtMfB8t4mzXVqBjpz
|
||||
2csMqOnNvo7bctfpJkjM14UKib39MR2wUv9fD6Qa+OAAIeXGTQH+wlXmlYjji9+A
|
||||
4tgq/+d75qUC/tyHSgbZLNXobHF8v77g60cBvFXVL02W53xhVDZP4gwu5iSSN8BJ
|
||||
a2hqwo4UO53mRUNkwFZONYxJE7MhLl22r08eu0xNYhoGtpHzDVoyHg26+2FUgFDd
|
||||
TNsdqjMyJ+3GXEE3PdKVDTj9To+RoHLuCczk5uvtFYGhseRwIWbVhmTLKUL+wgSa
|
||||
+b90slkv+CBJvLjvKbVCmCLXwiH8Cx+MZSu0oM5v8fbHuWOhkb7bJd1V+U7qV/OA
|
||||
CCqBICt64F+ooQ0oEdC0oLvr2LkCDQRlpUrXARAA1DKsF2ZNUdPIn4VcsjRk/+qF
|
||||
13VC9SaqMp+J+8m1XTIeXdr27uUa2vT4j8pAM4gwMVkpEqE0rmHK+S1SeEAlcizC
|
||||
Bvp7vvso/glcOg9Sgt9PXvvEDPL/Hnsn1+3YX+Gye4cOTiDDgVW1RKcgGj9Xsir+
|
||||
5BS9Secj5CGo92cuaqIo/mMjxGlsuW/LvTU5qQhz7aOaBibe5EHPlGMqM6XJN0BZ
|
||||
MHRfBiGDs2n/egMnTPL0JcTlAeird+yxDPULKzhQWkd8rfQKpwcRiY6IcYFHlWdM
|
||||
VhZkXNRrxh6+q3rR7FKmxlvG/12YyT6Y1BocGLgROzKIeoEp+6vsU5LJ90jy82ig
|
||||
oGSHwNjm2RRukjV3eebovl1dCo6IaI/j4idCv7NlcBnln/Unk4YOZbneMT5r+3Zy
|
||||
Q4azLB8KHfHOrUwAxRAGPygdLtqbjs4mF45HDe6h3IOVoiOQlZNpesrwEumlK+Il
|
||||
taU0T8hfxyMpIcTLUZpIddSxo0sVby2XZ+z00En3JvtqbpRcfA87thxpsE7uHxwT
|
||||
YT8mPPDxo1R4I4LSzsDnekD8EB/7woz4n5I1RBoPB1LSoo0B2os+4vHGkiwZ0TN0
|
||||
ICcUYdM623Bv2wJQbVKEDvwjHZTkotjLx7R2lyqMRwFYrMXHxevOfbARJQCqrcY2
|
||||
ouLzQme9rE5MPQbKj2cAEQEAAYkCNgQYAQoAIBYhBKTZIo5Vdh5mW/Acu1zoact9
|
||||
7ASMBQJlpUrXAhsMAAoJEFzoact97ASMNsIP/3tlsvwUVfy19lUjxWT4rPw2GGz8
|
||||
lbPiaetgigK1F1rlzYnIVo32Fcj/GNNwWEdxxEzeaQR/AJmZLWB8sBDThoTGeSDK
|
||||
fjKXeDjZh+ElpIKWyk7f3ddHN2TpBz698kZ7fYCciRE9T4d3xgbqx2rCfupxUFSj
|
||||
lxLFRkasByJnLdAZI50NZjW838IHMaGsvgbWEqRuvKZOES6gFhrK1NTSxj5iuiHk
|
||||
Uxj1KzMhOW+m1eZ0pQcCVXJDY6KYhmrZzw9q6kzSO9ukmS5yRf0EnD7Fsca4iIXP
|
||||
Y28xs3zBxYHV4IGU1PtcIwNewmTnjnEy0apHPz0zDplHi1meXuhA7bBMjs/AouJg
|
||||
6FIDNSQqDuFXufqvVQ6LZZgob+LklMAoGcka4/5ZLPjipj5SWNeZZunJujSqWK7f
|
||||
KJaIfn7ILXqxjaTFrjBN3cm60rO1+zEektrjtWMmSBn0L76pY2ucenrqewruYYdD
|
||||
12VQra/6QAS5R0HG8gzOfsZcrHaiIuLoTbsOgnqLVcdb9lO7f3oMbKPwejZ5yhyz
|
||||
SraXHvmixlhf4uUYwsWyhw3UgHrv1psB8Z9NfdH9/T2BvRg0qy6ZmI0n0OagPNgz
|
||||
v+SZrqrWkSjyPdl6j7x8EmePfNidqw/CnncYI2rEVSmP28W0Uhg5JLgroGYmycv6
|
||||
HeZaRpYvkV8UNmnE
|
||||
=BtHq
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
||||
pub rsa4096 2024-03-10 [SC]
|
||||
298A8AA3D25AFD95D5C89C63C8815953907B66AD
|
||||
uid [ultimate] Ruihang Lai (CODE SIGNING KEY) <ruihangl@apache.org>
|
||||
sig 3 C8815953907B66AD 2024-03-10 [self-signature]
|
||||
sub rsa4096 2024-03-10 [E]
|
||||
sig C8815953907B66AD 2024-03-10 [self-signature]
|
||||
|
||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
|
||||
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
|
||||
2KO2FSofA649SDc2HheDeQ==
|
||||
=yNdl
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
||||
@@ -0,0 +1,229 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright {yyyy} {name of copyright owner}
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
------------------------------------------------------------------------------------
|
||||
This product bundles various third-party components under other open source licenses.
|
||||
This section summarizes those components and their licenses. See licenses/
|
||||
and 3rdparty/tvm-ffi/licenses/ for text of these licenses.
|
||||
|
||||
|
||||
Apache Software Foundation License 2.0
|
||||
--------------------------------------
|
||||
|
||||
3rdparty/OpenCL-Headers
|
||||
3rdparty/cutlass_fpA_intB_gemm
|
||||
3rdparty/tensorrt_llm
|
||||
3rdparty/tvm-ffi/3rdparty/dlpack
|
||||
|
||||
|
||||
MIT License
|
||||
-----------
|
||||
|
||||
3rdparty/compiler-rt/builtin_fp16.h
|
||||
|
||||
|
||||
BSD 3-Clause "New" or "Revised" License
|
||||
---------------------------------------
|
||||
|
||||
3rdparty/cutlass
|
||||
3rdparty/libflash_attn
|
||||
3rdparty/tvm-ffi/3rdparty/libbacktrace
|
||||
@@ -0,0 +1,5 @@
|
||||
Apache TVM
|
||||
Copyright 2019-2023 The Apache Software Foundation
|
||||
|
||||
This product includes software developed at
|
||||
The Apache Software Foundation (http://www.apache.org/).
|
||||
@@ -0,0 +1,65 @@
|
||||
<!--- Licensed to the Apache Software Foundation (ASF) under one -->
|
||||
<!--- or more contributor license agreements. See the NOTICE file -->
|
||||
<!--- distributed with this work for additional information -->
|
||||
<!--- regarding copyright ownership. The ASF licenses this file -->
|
||||
<!--- to you under the Apache License, Version 2.0 (the -->
|
||||
<!--- "License"); you may not use this file except in compliance -->
|
||||
<!--- with the License. You may obtain a copy of the License at -->
|
||||
|
||||
<!--- http://www.apache.org/licenses/LICENSE-2.0 -->
|
||||
|
||||
<!--- Unless required by applicable law or agreed to in writing, -->
|
||||
<!--- software distributed under the License is distributed on an -->
|
||||
<!--- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -->
|
||||
<!--- KIND, either express or implied. See the License for the -->
|
||||
<!--- specific language governing permissions and limitations -->
|
||||
<!--- under the License. -->
|
||||
|
||||
<img src=https://raw.githubusercontent.com/apache/tvm-site/main/images/logo/tvm-logo-small.png width=128/> Open Machine Learning Compiler Framework
|
||||
==============================================
|
||||
[Documentation](https://tvm.apache.org/docs) |
|
||||
[Contributors](CONTRIBUTORS.md) |
|
||||
[Community](https://tvm.apache.org/community) |
|
||||
[Release Notes](NEWS.md)
|
||||
|
||||
Apache TVM is an open machine learning compilation framework,
|
||||
following the following principles:
|
||||
|
||||
- Python-first development that enables quick customization of machine learning compiler pipelines.
|
||||
- Universal deployment to bring models into minimum deployable modules.
|
||||
|
||||
License
|
||||
-------
|
||||
TVM is licensed under the [Apache-2.0](LICENSE) license.
|
||||
|
||||
Getting Started
|
||||
---------------
|
||||
Check out the [TVM Documentation](https://tvm.apache.org/docs/) site for installation instructions, tutorials, examples, and more.
|
||||
The [Getting Started with TVM](https://tvm.apache.org/docs/get_started/overview.html) tutorial is a great
|
||||
place to start.
|
||||
|
||||
Contribute to TVM
|
||||
-----------------
|
||||
TVM adopts the Apache committer model. We aim to create an open-source project maintained and owned by the community.
|
||||
Check out the [Contributor Guide](https://tvm.apache.org/docs/contribute/).
|
||||
|
||||
History and Acknowledgement
|
||||
---------------------------
|
||||
TVM started as a research project for deep learning compilation.
|
||||
The first version of the project benefited a lot from the following projects:
|
||||
|
||||
- [Halide](https://github.com/halide/Halide): Part of TVM's TIR and arithmetic simplification module
|
||||
originates from Halide. We also learned and adapted some parts of the lowering pipeline from Halide.
|
||||
- [Loopy](https://github.com/inducer/loopy): use of integer set analysis and its loop transformation primitives.
|
||||
- [Theano](https://github.com/Theano/Theano): the design inspiration of symbolic scan operator for recurrence.
|
||||
|
||||
Since then, the project has gone through several rounds of redesigns.
|
||||
The current design is also drastically different from the initial design, following the
|
||||
development trend of the ML compiler community.
|
||||
|
||||
The most recent version focuses on a cross-level design with TensorIR as the tensor-level representation
|
||||
and Relax as the graph-level representation and Python-first transformations.
|
||||
The project's current design goal is to make the ML compiler accessible by enabling most
|
||||
transformations to be customizable in Python and bringing a cross-level representation that can jointly
|
||||
optimize computational graphs, tensor programs, and libraries. The project is also a foundation
|
||||
infra for building Python-first vertical compilers for domains, such as LLMs.
|
||||
@@ -0,0 +1,7 @@
|
||||
# WeHub 来源说明
|
||||
|
||||
- 原始项目:`apache/tvm`
|
||||
- 原始仓库:https://github.com/apache/tvm
|
||||
- 导入方式:上游默认分支的最新快照
|
||||
- 原作者、版权和许可证信息以原始仓库及本仓库 LICENSE 为准
|
||||
- 本文件仅用于记录来源,不代表 WeHub 是原项目作者
|
||||
@@ -0,0 +1,15 @@
|
||||
*.iml
|
||||
.gradle
|
||||
/local.properties
|
||||
/.idea/workspace.xml
|
||||
/.idea/libraries
|
||||
.DS_Store
|
||||
/build
|
||||
/captures
|
||||
.externalNativeBuild
|
||||
|
||||
/app/src/main/jni/jni_helper_func.h
|
||||
/app/src/main/jni/org_apache_tvm_native_c_api.cc
|
||||
/app/src/main/jni/org_apache_tvm_native_c_api.h
|
||||
/app/src/main/obj/
|
||||
dev_tools/tvmrpc.keystore
|
||||
@@ -0,0 +1,170 @@
|
||||
<!--- Licensed to the Apache Software Foundation (ASF) under one -->
|
||||
<!--- or more contributor license agreements. See the NOTICE file -->
|
||||
<!--- distributed with this work for additional information -->
|
||||
<!--- regarding copyright ownership. The ASF licenses this file -->
|
||||
<!--- to you under the Apache License, Version 2.0 (the -->
|
||||
<!--- "License"); you may not use this file except in compliance -->
|
||||
<!--- with the License. You may obtain a copy of the License at -->
|
||||
|
||||
<!--- http://www.apache.org/licenses/LICENSE-2.0 -->
|
||||
|
||||
<!--- Unless required by applicable law or agreed to in writing, -->
|
||||
<!--- software distributed under the License is distributed on an -->
|
||||
<!--- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -->
|
||||
<!--- KIND, either express or implied. See the License for the -->
|
||||
<!--- specific language governing permissions and limitations -->
|
||||
<!--- under the License. -->
|
||||
|
||||
|
||||
# Android TVM RPC
|
||||
|
||||
This folder contains Android RPC app that allows us to launch an RPC server on a Android device and connect to it through python script and do testing on the python side as normal TVM RPC.
|
||||
|
||||
You will need JDK, [Android NDK](https://developer.android.com/ndk) and an Android device to use this.
|
||||
|
||||
## Build and Installation
|
||||
|
||||
### <a name="buildapk">Build APK</a>
|
||||
|
||||
We use [Gradle](https://gradle.org) to build. Please follow [the installation instruction](https://gradle.org/install) for your operating system.
|
||||
|
||||
Before you build the Android application, please refer to [TVM4J Installation Guide](https://github.com/apache/tvm/blob/main/jvm/README.md) and install tvm4j-core to your local maven repository. You can find tvm4j dependency declare in `app/build.gradle`. Modify it if it is necessary.
|
||||
|
||||
```
|
||||
dependencies {
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
androidTestImplementation('androidx.test.espresso:espresso-core:3.1.0', {
|
||||
exclude group: 'com.android.support', module: 'support-annotations'
|
||||
})
|
||||
implementation 'androidx.appcompat:appcompat:1.6.1'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
|
||||
implementation 'com.google.android.material:material:1.8.0'
|
||||
implementation files('../../../jvm/core/target/tvm4j-core-0.0.1-SNAPSHOT.jar')
|
||||
testImplementation 'junit:junit:4.13.2'
|
||||
}
|
||||
```
|
||||
|
||||
Now use Gradle to compile JNI, resolve Java dependencies and build the Android application together with tvm4j. Run following script to generate the apk file.
|
||||
|
||||
```bash
|
||||
export ANDROID_HOME=[Path to your Android SDK, e.g., ~/Android/sdk]
|
||||
cd apps/android_rpc
|
||||
gradle clean build
|
||||
```
|
||||
|
||||
In `app/build/outputs/apk` you'll find `app-release-unsigned.apk`, use `dev_tools/gen_keystore.sh` to generate a signature and use `dev_tools/sign_apk.sh` to get the signed apk file `app/build/outputs/apk/release/tvmrpc-release.apk`.
|
||||
|
||||
Upload `tvmrpc-release.apk` to your Android device and install it:
|
||||
|
||||
```bash
|
||||
$ANDROID_HOME/platform-tools/adb install app/build/outputs/apk/release/tvmrpc-release.apk
|
||||
```
|
||||
|
||||
If you see error:
|
||||
|
||||
adb: failed to install app/build/outputs/apk/release/tvmrpc-release.apk:
|
||||
Failure [INSTALL_FAILED_UPDATE_INCOMPATIBLE:
|
||||
Package org.apache.tvm.tvmrpc signatures do not match the previously installed version; ignoring!]
|
||||
|
||||
Run uninstall first:
|
||||
|
||||
```bash
|
||||
$ANDROID_HOME/platform-tools/adb uninstall org.apache.tvm.tvmrpc
|
||||
```
|
||||
|
||||
### Build with OpenCL
|
||||
|
||||
Application is building with OpenCL support by default.
|
||||
[OpenCL-wrapper](../../src/runtime/opencl/opencl_wrapper) is used and will dynamically load OpenCL library on the device.
|
||||
If the device doesn't have OpenCL library on it, then you'll see in the runtime that OpenCL library cannot be opened.
|
||||
If you want to build this application without OpenCL then set `USE_OPENCL = 0`
|
||||
in [config.mk](./app/src/main/jni/make/config.mk)
|
||||
|
||||
## Cross Compile and Run on Android Devices
|
||||
|
||||
### Architecture and Android Standalone Toolchain
|
||||
|
||||
In order to cross compile a shared library (.so) for your android device, you have to know the target triple for the device. (Refer to [Cross-compilation using Clang](https://clang.llvm.org/docs/CrossCompilation.html) for more information). Run `adb shell cat /proc/cpuinfo` to list the device's CPU information.
|
||||
|
||||
Now use NDK to generate standalone toolchain for your device. For my test device, I use following command.
|
||||
|
||||
```bash
|
||||
cd /opt/android-ndk/build/tools/
|
||||
./make-standalone-toolchain.sh --platform=android-24 --use-llvm --arch=arm64 --install-dir=/opt/android-toolchain-arm64
|
||||
```
|
||||
|
||||
If everything goes well, you will find compile tools in `/opt/android-toolchain-arm64/bin`. For example, `bin/aarch64-linux-android-g++` can be used to compile C++ source codes and create shared libraries for arm64 Android devices.
|
||||
|
||||
### Cross Compile and Upload to the Android Device
|
||||
|
||||
First start an RPC tracker using
|
||||
|
||||
```python -m tvm.exec.rpc_tracker --port [PORT]```
|
||||
|
||||
and connect your Android device to this RPC tracker via the TVM RPC application. Open the app,
|
||||
set the `Address` and `Port` fields to the address and port of the RPC tracker respectively.
|
||||
The key should be set to "android" if you wish to avoid modifying the default test script.
|
||||
|
||||
After pushing "START RPC" button on the app, you can check the connect by run
|
||||
|
||||
```python -m tvm.exec.query_rpc_tracker --port [PORT]```
|
||||
|
||||
on your host machine.
|
||||
You are supposed to find a free "android" in the queue status.
|
||||
|
||||
```
|
||||
...
|
||||
|
||||
Queue Status
|
||||
-------------------------------
|
||||
key total free pending
|
||||
-------------------------------
|
||||
android 1 1 0
|
||||
-------------------------------
|
||||
```
|
||||
|
||||
|
||||
Then checkout [android\_rpc/tests/android\_rpc\_test.py](https://github.com/apache/tvm/blob/main/apps/android_rpc/tests/android_rpc_test.py) and run,
|
||||
|
||||
```bash
|
||||
# Specify the RPC tracker
|
||||
export TVM_TRACKER_HOST=0.0.0.0
|
||||
export TVM_TRACKER_PORT=[PORT]
|
||||
# Specify the standalone Android C++ compiler
|
||||
export TVM_NDK_CC=/opt/android-toolchain-arm64/bin/aarch64-linux-android-g++
|
||||
python android_rpc_test.py
|
||||
```
|
||||
|
||||
This will compile TVM IR to shared libraries (CPU, OpenCL and Vulkan) and run vector addition on your Android device. To verify compiled TVM IR shared libraries on OpenCL target set `'test_opencl = True'` and on Vulkan target set `'test_vulkan = True'` in [tests/android_rpc_test.py](https://github.com/apache/tvm/blob/main/apps/android_rpc/tests/android_rpc_test.py), by default on CPU target will execute.
|
||||
On my test device, it gives following results.
|
||||
|
||||
```bash
|
||||
Run CPU test ...
|
||||
0.000962932 secs/op
|
||||
|
||||
Run GPU(OpenCL Flavor) test ...
|
||||
0.000155807 secs/op
|
||||
|
||||
[23:29:34] /home/tvm/src/runtime/vulkan/vulkan_device_api.cc:674: Cannot initialize vulkan: [23:29:34] /home/tvm/src/runtime/vulkan/vulkan_device_api.cc:512: Check failed: __e == VK_SUCCESS Vulan Error, code=-9: VK_ERROR_INCOMPATIBLE_DRIVER
|
||||
|
||||
Stack trace returned 10 entries:
|
||||
[bt] (0) /home/user/.local/lib/python3.6/site-packages/tvm-0.4.0-py3.6-linux-x86_64.egg/tvm/libtvm.so(dmlc::StackTrace[abi:cxx11]()+0x53) [0x7f477f5399f3]
|
||||
.........
|
||||
|
||||
You can still compile vulkan module but cannot run locally
|
||||
Run GPU(Vulkan Flavor) test ...
|
||||
0.000225198 secs/op
|
||||
```
|
||||
|
||||
You can define your own TVM operators and test via this RPC app on your Android device to find the most optimized TVM schedule.
|
||||
|
||||
### Troubleshooting
|
||||
|
||||
If you build the application in Android Studio and see error similar to this one:
|
||||
```
|
||||
A problem occurred evaluating project ':app'.
|
||||
> Failed to apply plugin 'com.android.internal.version-check'.
|
||||
> Minimum supported Gradle version is 7.5. Current version is 7.4. If using the gradle wrapper, try editing the distributionUrl in /Users/echuraev/Workspace/OctoML/tvm_android_test/apps/android_deploy/gradle/wrapper/gradle-wrapper.properties to gradle-7.5-all.zip
|
||||
```
|
||||
Run project syncing `File -> Sync Project with Gradle Files`. It should sync the
|
||||
project and create gradle-wrapper files.
|
||||
@@ -0,0 +1 @@
|
||||
/build
|
||||
@@ -0,0 +1,103 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
apply plugin: 'com.android.application'
|
||||
|
||||
task generateJniHeaders(type: Exec, description: 'Generate JNI Headers') {
|
||||
def headerPath = "${project.projectDir}/src/main/jni"
|
||||
def classPath = "${project.projectDir}/../../../jvm/core/target/*"
|
||||
def filePath = "${project.projectDir}/../../../jvm/core/src/main/java/org/apache/tvm/LibInfo.java"
|
||||
commandLine "javac", "-h", headerPath, "-classpath", classPath, filePath
|
||||
doLast {
|
||||
file("${headerPath}/org_apache_tvm_LibInfo.h").renameTo(file("${headerPath}/org_apache_tvm_native_c_api.h"))
|
||||
}
|
||||
}
|
||||
|
||||
task copyFiles(type: Copy, description: 'Copy Sources for ndk-build') {
|
||||
dependsOn "generateJniHeaders"
|
||||
def ndkFilesPath = "${project.projectDir}/../../../jvm/native/src/main/native"
|
||||
def srcPath = "${project.projectDir}/src/main/jni/"
|
||||
|
||||
from "${ndkFilesPath}/org_apache_tvm_native_c_api.cc", "${ndkFilesPath}/jni_helper_func.h"
|
||||
into srcPath
|
||||
}
|
||||
|
||||
task deleteLibs(type: Delete, description: "Delete Compiled Libraries") {
|
||||
dependsOn "copyFiles"
|
||||
def libsPath = "${project.projectDir}/src/main/libs"
|
||||
delete libsPath
|
||||
}
|
||||
|
||||
task buildJni(type: Exec, description: 'Build JNI libs') {
|
||||
dependsOn "deleteLibs"
|
||||
def buildPath = "${project.projectDir}/src/main/jni"
|
||||
commandLine "ndk-build", "--directory", buildPath
|
||||
}
|
||||
|
||||
tasks.withType(JavaCompile) {
|
||||
compileTask -> compileTask.dependsOn buildJni
|
||||
}
|
||||
|
||||
// gradle.projectsEvaluated {
|
||||
// tasks.withType(JavaCompile) {
|
||||
// options.compilerArgs << "-Xlint:deprecation"
|
||||
// }
|
||||
// }
|
||||
|
||||
android {
|
||||
compileSdkVersion 33
|
||||
defaultConfig {
|
||||
applicationId "org.apache.tvm.tvmrpc"
|
||||
minSdkVersion 24
|
||||
targetSdkVersion 33
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
|
||||
}
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
sourceSets {
|
||||
main {
|
||||
jni.srcDirs = []
|
||||
jniLibs.srcDirs = ['src/main/libs']
|
||||
}
|
||||
}
|
||||
|
||||
lint {
|
||||
disable 'Instantiatable' // MainActivity and RPCActivity must extend android.app.Activity
|
||||
disable 'MissingClass' // .RPCWatchdogService was not found in the project or the libraries
|
||||
disable 'IconDipSize' // The image ic_launcher.png varies significantly in its density-independent size
|
||||
}
|
||||
namespace 'org.apache.tvm.tvmrpc'
|
||||
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
androidTestImplementation('androidx.test.espresso:espresso-core:3.1.0', {
|
||||
exclude group: 'com.android.support', module: 'support-annotations'
|
||||
})
|
||||
implementation 'androidx.appcompat:appcompat:1.6.1'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
|
||||
implementation 'com.google.android.material:material:1.8.0'
|
||||
implementation files('../../../jvm/core/target/tvm4j-core-0.0.1-SNAPSHOT.jar')
|
||||
testImplementation 'junit:junit:4.13.2'
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<!--
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
-->
|
||||
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:label="@string/app_name"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/AppTheme"
|
||||
android:icon="@mipmap/ic_launcher">
|
||||
<uses-native-library
|
||||
android:name="libOpenCL.so"
|
||||
android:required="false"/>
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:theme="@style/AppTheme.NoActionBar"
|
||||
android:screenOrientation="unspecified"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<service android:name=".RPCWatchdogService"
|
||||
android:process=":RPCWatchdogServiceProcess"
|
||||
android:permission="android.permission.BIND_JOB_SERVICE" />
|
||||
<activity
|
||||
android:name=".RPCActivity"
|
||||
android:process=":RPCProcess"
|
||||
android:label="@string/rpc_name"
|
||||
android:theme="@style/AppTheme.NoActionBar"
|
||||
android:exported="false"
|
||||
android:screenOrientation="unspecified">
|
||||
</activity>
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.tvm.tvmrpc;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.widget.CompoundButton;
|
||||
import android.widget.EditText;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.widget.SwitchCompat;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
|
||||
public class MainActivity extends AppCompatActivity {
|
||||
// wait time before automatic restart of RPC Activity
|
||||
public static final int HANDLER_RESTART_DELAY = 5000;
|
||||
|
||||
private void showDialog(String title, String msg) {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||
builder.setTitle(title);
|
||||
builder.setMessage(msg);
|
||||
builder.setCancelable(true);
|
||||
builder.setNeutralButton(android.R.string.ok, new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int id) {
|
||||
dialog.cancel();
|
||||
}
|
||||
});
|
||||
builder.create().show();
|
||||
}
|
||||
|
||||
public Intent updateRPCPrefs() {
|
||||
System.err.println("updating preferences...");
|
||||
EditText edProxyAddress = findViewById(R.id.input_address);
|
||||
EditText edProxyPort = findViewById(R.id.input_port);
|
||||
EditText edAppKey = findViewById(R.id.input_key);
|
||||
SwitchCompat inputSwitch = findViewById(R.id.switch_persistent);
|
||||
|
||||
final String proxyHost = edProxyAddress.getText().toString();
|
||||
final int proxyPort = Integer.parseInt(edProxyPort.getText().toString());
|
||||
final String key = edAppKey.getText().toString();
|
||||
final boolean isChecked = inputSwitch.isChecked();
|
||||
|
||||
SharedPreferences pref =
|
||||
getApplicationContext().getSharedPreferences("RPCProxyPreference", Context.MODE_PRIVATE);
|
||||
SharedPreferences.Editor editor = pref.edit();
|
||||
editor.putString("input_address", proxyHost);
|
||||
editor.putString("input_port", edProxyPort.getText().toString());
|
||||
editor.putString("input_key", key);
|
||||
editor.putBoolean("input_switch", isChecked);
|
||||
editor.commit();
|
||||
|
||||
Intent intent = new Intent(this, RPCActivity.class);
|
||||
intent.putExtra("host", proxyHost);
|
||||
intent.putExtra("port", proxyPort);
|
||||
intent.putExtra("key", key);
|
||||
return intent;
|
||||
}
|
||||
|
||||
private void setupRelaunch() {
|
||||
final Context context = this;
|
||||
final SwitchCompat switchPersistent = findViewById(R.id.switch_persistent);
|
||||
final Runnable rPCStarter = new Runnable() {
|
||||
public void run() {
|
||||
if (switchPersistent.isChecked()) {
|
||||
System.err.println("relaunching RPC activity...");
|
||||
Intent intent = ((MainActivity) context).updateRPCPrefs();
|
||||
startActivity(intent);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Handler handler = new Handler(Looper.getMainLooper());
|
||||
handler.postDelayed(rPCStarter, HANDLER_RESTART_DELAY);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_main);
|
||||
Toolbar toolbar = findViewById(R.id.toolbar);
|
||||
setSupportActionBar(toolbar);
|
||||
final Context context = this;
|
||||
|
||||
SwitchCompat switchPersistent = findViewById(R.id.switch_persistent);
|
||||
switchPersistent.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
||||
if (isChecked) {
|
||||
System.err.println("automatic RPC restart enabled...");
|
||||
updateRPCPrefs();
|
||||
setupRelaunch();
|
||||
} else {
|
||||
System.err.println("automatic RPC restart disabled...");
|
||||
updateRPCPrefs();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
enableInputView(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
System.err.println("MainActivity onResume...");
|
||||
enableInputView(true);
|
||||
setupRelaunch();
|
||||
super.onResume();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
private void enableInputView(boolean enable) {
|
||||
EditText edProxyAddress = findViewById(R.id.input_address);
|
||||
EditText edProxyPort = findViewById(R.id.input_port);
|
||||
EditText edAppKey = findViewById(R.id.input_key);
|
||||
SwitchCompat input_switch = findViewById(R.id.switch_persistent);
|
||||
edProxyAddress.setEnabled(enable);
|
||||
edProxyPort.setEnabled(enable);
|
||||
edAppKey.setEnabled(enable);
|
||||
|
||||
if (enable) {
|
||||
SharedPreferences pref =
|
||||
getApplicationContext().getSharedPreferences("RPCProxyPreference", Context.MODE_PRIVATE);
|
||||
String inputAddress = pref.getString("input_address", null);
|
||||
if (null != inputAddress)
|
||||
edProxyAddress.setText(inputAddress);
|
||||
String inputPort = pref.getString("input_port", null);
|
||||
if (null != inputPort)
|
||||
edProxyPort.setText(inputPort);
|
||||
String inputKey = pref.getString("input_key", null);
|
||||
if (null != inputKey)
|
||||
edAppKey.setText(inputKey);
|
||||
boolean isChecked = pref.getBoolean("input_switch", false);
|
||||
input_switch.setChecked(isChecked);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.tvm.tvmrpc;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
public class RPCActivity extends AppCompatActivity {
|
||||
private RPCProcessor tvmServerWorker;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_rpc);
|
||||
|
||||
Button stopRPC = findViewById(R.id.button_stop_rpc);
|
||||
stopRPC.setOnClickListener(new View.OnClickListener() {
|
||||
public void onClick(View v) {
|
||||
System.err.println(tvmServerWorker == null);
|
||||
if (tvmServerWorker != null) {
|
||||
// currently will raise a socket closed exception
|
||||
tvmServerWorker.disconnect();
|
||||
}
|
||||
finish();
|
||||
// prevent Android from recycling the process
|
||||
System.exit(0);
|
||||
}
|
||||
});
|
||||
|
||||
System.err.println("rpc activity onCreate...");
|
||||
Intent intent = getIntent();
|
||||
String host = intent.getStringExtra("host");
|
||||
int port = intent.getIntExtra("port", 9090);
|
||||
String key = intent.getStringExtra("key");
|
||||
|
||||
tvmServerWorker = new RPCProcessor(this);
|
||||
tvmServerWorker.setDaemon(true);
|
||||
tvmServerWorker.start();
|
||||
tvmServerWorker.connect(host, port, key);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
System.err.println("rpc activity onDestroy");
|
||||
tvmServerWorker.disconnect();
|
||||
super.onDestroy();
|
||||
android.os.Process.killProcess(android.os.Process.myPid());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.tvm.tvmrpc;
|
||||
|
||||
import android.app.Activity;
|
||||
import org.apache.tvm.rpc.RPCWatchdog;
|
||||
|
||||
/**
|
||||
* Watchdog for Android RPC.
|
||||
*/
|
||||
public class RPCAndroidWatchdog extends RPCWatchdog {
|
||||
public Activity rpc_activity = null;
|
||||
public RPCAndroidWatchdog(Activity activity) {
|
||||
super();
|
||||
rpc_activity = activity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to non-destructively terminate the running thread on Android
|
||||
*/
|
||||
@Override
|
||||
protected void terminate() {
|
||||
rpc_activity.finish();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.tvm.tvmrpc;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import java.net.Socket;
|
||||
import org.apache.tvm.rpc.ConnectTrackerServerProcessor;
|
||||
|
||||
/**
|
||||
* Connect to RPC proxy and deal with requests.
|
||||
*/
|
||||
class RPCProcessor extends Thread {
|
||||
private String host;
|
||||
private int port;
|
||||
private String key;
|
||||
private boolean running = false;
|
||||
private long startTime;
|
||||
private ConnectTrackerServerProcessor currProcessor;
|
||||
private boolean first = true;
|
||||
private Activity rpc_activity = null;
|
||||
|
||||
public RPCProcessor(Activity activity) {
|
||||
super();
|
||||
rpc_activity = activity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
RPCAndroidWatchdog watchdog = new RPCAndroidWatchdog(rpc_activity);
|
||||
watchdog.start();
|
||||
while (true) {
|
||||
synchronized (this) {
|
||||
currProcessor = null;
|
||||
while (!running) {
|
||||
try {
|
||||
this.wait();
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
}
|
||||
try {
|
||||
currProcessor = new ConnectTrackerServerProcessor(host, port, key, watchdog);
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
// kill if creating a new processor failed
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
if (currProcessor != null)
|
||||
currProcessor.run();
|
||||
watchdog.finishTimeout();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnect from the proxy server.
|
||||
*/
|
||||
synchronized void disconnect() {
|
||||
if (running) {
|
||||
running = false;
|
||||
if (currProcessor != null) {
|
||||
currProcessor.terminate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Start rpc processor and connect to the proxy server.
|
||||
* @param host proxy server host.
|
||||
* @param port proxy server port.
|
||||
* @param key proxy server key.
|
||||
*/
|
||||
synchronized void connect(String host, int port, String key) {
|
||||
this.host = host;
|
||||
this.port = port;
|
||||
this.key = key;
|
||||
running = true;
|
||||
this.notify();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
MY_PATH := $(LOCAL_PATH)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_PATH := $(MY_PATH)
|
||||
ROOT_PATH := $(MY_PATH)/../../../../../..
|
||||
|
||||
ifndef config
|
||||
ifneq ("$(wildcard ./config.mk)","")
|
||||
config ?= config.mk
|
||||
else
|
||||
config ?= make/config.mk
|
||||
endif
|
||||
endif
|
||||
|
||||
include $(config)
|
||||
|
||||
LOCAL_SRC_FILES := org_apache_tvm_native_c_api.cc
|
||||
LOCAL_LDFLAGS := -L$(SYSROOT)/usr/lib/ -llog
|
||||
|
||||
LOCAL_C_INCLUDES := $(ROOT_PATH)/include \
|
||||
$(ROOT_PATH)/3rdparty/tvm-ffi/include \
|
||||
$(ROOT_PATH)/3rdparty/tvm-ffi/3rdparty/dlpack/include \
|
||||
$(ROOT_PATH)/3rdparty/OpenCL-Headers
|
||||
|
||||
LOCAL_MODULE = tvm4j_runtime_packed
|
||||
|
||||
LOCAL_CPP_FEATURES += exceptions
|
||||
LOCAL_LDLIBS += -latomic
|
||||
LOCAL_ARM_MODE := arm
|
||||
|
||||
ifdef ADD_C_INCLUDES
|
||||
LOCAL_C_INCLUDES += $(ADD_C_INCLUDES)
|
||||
endif
|
||||
|
||||
ifdef ADD_LDLIBS
|
||||
LOCAL_LDLIBS += $(ADD_LDLIBS)
|
||||
endif
|
||||
|
||||
include $(BUILD_SHARED_LIBRARY)
|
||||
@@ -0,0 +1,50 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
ifndef config
|
||||
ifneq ("$(wildcard ./config.mk)","")
|
||||
config ?= config.mk
|
||||
else
|
||||
config ?= make/config.mk
|
||||
endif
|
||||
endif
|
||||
|
||||
include $(config)
|
||||
|
||||
# We target every architecture except armeabi here, for two reasons:
|
||||
# 1) armeabi is deprecated in NDK r16 and removed in r17
|
||||
# 2) vulkan is not supported in armeabi
|
||||
APP_ABI ?= armeabi-v7a arm64-v8a x86 x86_64 mips
|
||||
APP_STL := c++_shared
|
||||
|
||||
APP_CPPFLAGS += -DTVM4J_ANDROID=1 -std=c++17 -Oz -frtti
|
||||
ifeq ($(USE_OPENCL), 1)
|
||||
APP_CPPFLAGS += -DTVM_OPENCL_RUNTIME=1
|
||||
endif
|
||||
|
||||
ifeq ($(USE_VULKAN), 1)
|
||||
APP_CPPFLAGS += -DTVM_VULKAN_RUNTIME=1
|
||||
APP_LDFLAGS += -lvulkan
|
||||
endif
|
||||
|
||||
ifeq ($(USE_SORT), 1)
|
||||
APP_CPPFLAGS += -DUSE_SORT=1
|
||||
endif
|
||||
|
||||
ifeq ($(USE_RANDOM), 1)
|
||||
APP_CPPFLAGS += -DUSE_RANDOM=1
|
||||
endif
|
||||
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \file tvm_runtime.h
|
||||
* \brief Pack all tvm runtime source files
|
||||
*/
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <fstream>
|
||||
|
||||
/* Enable custom logging - this will cause TVM to use a custom implementation
|
||||
* of tvm::runtime::detail::LogMessage. We use this to pass TVM log messages to
|
||||
* Android logcat.
|
||||
*/
|
||||
#define TVM_LOG_CUSTOMIZE 1
|
||||
#define TVM_FFI_USE_LIBBACKTRACE 0
|
||||
|
||||
#include "../3rdparty/tvm-ffi/src/ffi/backtrace.cc"
|
||||
#include "../3rdparty/tvm-ffi/src/ffi/container.cc"
|
||||
#include "../3rdparty/tvm-ffi/src/ffi/dtype.cc"
|
||||
#include "../3rdparty/tvm-ffi/src/ffi/error.cc"
|
||||
#include "../3rdparty/tvm-ffi/src/ffi/extra/library_module.cc"
|
||||
#include "../3rdparty/tvm-ffi/src/ffi/extra/library_module_dynamic_lib.cc"
|
||||
#include "../3rdparty/tvm-ffi/src/ffi/extra/library_module_system_lib.cc"
|
||||
#include "../3rdparty/tvm-ffi/src/ffi/extra/module.cc"
|
||||
#include "../3rdparty/tvm-ffi/src/ffi/function.cc"
|
||||
#include "../3rdparty/tvm-ffi/src/ffi/object.cc"
|
||||
#include "../3rdparty/tvm-ffi/src/ffi/tensor.cc"
|
||||
#include "../src/runtime/cpu_device_api.cc"
|
||||
#include "../src/runtime/device_api.cc"
|
||||
#include "../src/runtime/file_utils.cc"
|
||||
#include "../src/runtime/logging.cc"
|
||||
#include "../src/runtime/memory/memory_manager.cc"
|
||||
#include "../src/runtime/registry.cc"
|
||||
#include "../src/runtime/rpc/rpc_channel.cc"
|
||||
#include "../src/runtime/rpc/rpc_endpoint.cc"
|
||||
#include "../src/runtime/rpc/rpc_event_impl.cc"
|
||||
#include "../src/runtime/rpc/rpc_local_session.cc"
|
||||
#include "../src/runtime/rpc/rpc_module.cc"
|
||||
#include "../src/runtime/rpc/rpc_server_env.cc"
|
||||
#include "../src/runtime/rpc/rpc_session.cc"
|
||||
#include "../src/runtime/rpc/rpc_socket_impl.cc"
|
||||
#include "../src/runtime/tensor.cc"
|
||||
#include "../src/runtime/thread_pool.cc"
|
||||
#include "../src/runtime/threading_backend.cc"
|
||||
#include "../src/runtime/timer.cc"
|
||||
#include "../src/runtime/workspace_pool.cc"
|
||||
|
||||
#ifdef TVM_OPENCL_RUNTIME
|
||||
#include "../src/runtime/opencl/opencl_device_api.cc"
|
||||
#include "../src/runtime/opencl/opencl_module.cc"
|
||||
#include "../src/runtime/opencl/opencl_wrapper/opencl_wrapper.cc"
|
||||
#include "../src/runtime/source_utils.cc"
|
||||
#endif
|
||||
|
||||
#ifdef TVM_VULKAN_RUNTIME
|
||||
#include "../src/runtime/vulkan/vulkan_amdrgp.cc"
|
||||
#include "../src/runtime/vulkan/vulkan_buffer.cc"
|
||||
#include "../src/runtime/vulkan/vulkan_common.cc"
|
||||
#include "../src/runtime/vulkan/vulkan_device.cc"
|
||||
#include "../src/runtime/vulkan/vulkan_device_api.cc"
|
||||
#include "../src/runtime/vulkan/vulkan_instance.cc"
|
||||
#include "../src/runtime/vulkan/vulkan_module.cc"
|
||||
#include "../src/runtime/vulkan/vulkan_stream.cc"
|
||||
#include "../src/runtime/vulkan/vulkan_wrapped_func.cc"
|
||||
#endif
|
||||
|
||||
#ifdef USE_SORT
|
||||
#include "../src/runtime/extra/contrib/sort/sort.cc"
|
||||
#endif
|
||||
|
||||
#ifdef USE_RANDOM
|
||||
#include "../src/runtime/extra/contrib/random/random.cc"
|
||||
#endif
|
||||
|
||||
#include <android/log.h>
|
||||
|
||||
namespace tvm {
|
||||
namespace runtime {
|
||||
namespace detail {
|
||||
// Override logging mechanism
|
||||
[[noreturn]] void LogFatalImpl(const std::string& file, int lineno, const std::string& message) {
|
||||
std::string m = file + ":" + std::to_string(lineno) + ": " + message;
|
||||
__android_log_write(ANDROID_LOG_FATAL, "TVM_RUNTIME", m.c_str());
|
||||
throw tvm::ffi::Error("InternalError", message, TVMFFIBacktrace(file.c_str(), lineno, "", 0));
|
||||
}
|
||||
void LogMessageImpl(const std::string& file, int lineno, int level, const std::string& message) {
|
||||
std::string m = file + ":" + std::to_string(lineno) + ": " + message;
|
||||
__android_log_write(ANDROID_LOG_DEBUG + level, "TVM_RUNTIME", m.c_str());
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
} // namespace runtime
|
||||
} // namespace tvm
|
||||
@@ -0,0 +1,46 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<!--
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
-->
|
||||
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context="org.apache.tvm.tvmrpc.MainActivity">
|
||||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="match_parent"
|
||||
android:theme="@style/AppTheme.AppBarOverlay">
|
||||
|
||||
<androidx.appcompat.widget.Toolbar
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:background="?attr/colorPrimary"
|
||||
app:popupTheme="@style/AppTheme.PopupOverlay" />
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<include layout="@layout/content_main"/>
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
@@ -0,0 +1,46 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<!--
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
-->
|
||||
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context="org.apache.tvm.tvmrpc.RPCActivity">
|
||||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="match_parent"
|
||||
android:theme="@style/AppTheme.AppBarOverlay">
|
||||
|
||||
<androidx.appcompat.widget.Toolbar
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:background="?attr/colorPrimary"
|
||||
app:popupTheme="@style/AppTheme.PopupOverlay" />
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<include layout="@layout/content_rpc"/>
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
@@ -0,0 +1,106 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<!--
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
-->
|
||||
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
||||
tools:showIn="@layout/activity_main">
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content">
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/label_address"/>
|
||||
<EditText
|
||||
android:id="@+id/input_address"
|
||||
android:hint="@string/input_address"
|
||||
android:autofillHints="@string/label_address_hint"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:inputType="phone"
|
||||
android:background="@android:drawable/editbox_background"/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content">
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/label_port"/>
|
||||
<EditText
|
||||
android:id="@+id/input_port"
|
||||
android:hint="@string/input_port"
|
||||
android:autofillHints="@string/label_port_hint"
|
||||
android:minWidth="100dip"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:inputType="phone"
|
||||
android:background="@android:drawable/editbox_background"/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content">
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/label_key"/>
|
||||
<EditText
|
||||
android:id="@+id/input_key"
|
||||
android:hint="@string/input_key"
|
||||
android:autofillHints="@string/label_key_hint"
|
||||
android:inputType="text"
|
||||
android:minWidth="100dip"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@android:drawable/editbox_background"/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content">
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/label_persistent"/>
|
||||
<androidx.appcompat.widget.SwitchCompat
|
||||
android:id="@+id/switch_persistent"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:switchMinWidth="55dp"
|
||||
android:paddingLeft="10dip"
|
||||
android:paddingRight="10dip"
|
||||
android:checked="false"
|
||||
android:textOff="@string/switch_off"
|
||||
android:textOn="@string/switch_on" />
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,34 @@
|
||||
<?xml version='1.0'?>
|
||||
<!--
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
-->
|
||||
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
||||
tools:showIn="@layout/activity_rpc">
|
||||
<Button
|
||||
android:id="@+id/button_stop_rpc"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content"
|
||||
android:text="@string/stop_rpc" />
|
||||
</LinearLayout>
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 4.7 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.6 KiB |
@@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<!--
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
-->
|
||||
|
||||
<resources>
|
||||
<color name="colorPrimary">#3F51B5</color>
|
||||
<color name="colorPrimaryDark">#303F9F</color>
|
||||
<color name="colorAccent">#06d467</color>
|
||||
</resources>
|
||||
@@ -0,0 +1,43 @@
|
||||
<?xml version='1.0'?>
|
||||
<!--
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
-->
|
||||
|
||||
<resources>
|
||||
<string name="app_name">TVM RPC</string>
|
||||
<string name="rpc_name">RPC</string>
|
||||
|
||||
<string name="input_address">Enter the tracker server address</string>
|
||||
<string name="input_port">Enter the tracker server port</string>
|
||||
<string name="input_key">Enter the app connection key</string>
|
||||
|
||||
<string name="label_address">Address</string>
|
||||
<string name="label_port">Port</string>
|
||||
<string name="label_key">Key</string>
|
||||
<string name="label_persistent">Enable RPC</string>
|
||||
|
||||
<string name="label_address_hint">192.168.1.1</string>
|
||||
<string name="label_port_hint">9190</string>
|
||||
<string name="label_key_hint">android</string>
|
||||
|
||||
|
||||
<string name="switch_on">Enabled</string>
|
||||
<string name="switch_off">Disabled</string>
|
||||
|
||||
<string name="stop_rpc">Stop RPC</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,37 @@
|
||||
<?xml version='1.0'?>
|
||||
<!--
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
-->
|
||||
|
||||
<resources>
|
||||
|
||||
<!-- Base application theme. -->
|
||||
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
|
||||
<!-- Customize your theme here. -->
|
||||
<item name="colorPrimary">@color/colorPrimary</item>
|
||||
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
|
||||
<item name="colorAccent">@color/colorAccent</item>
|
||||
</style>
|
||||
<style name="AppTheme.NoActionBar">
|
||||
<item name="windowActionBar">false</item>
|
||||
<item name="windowNoTitle">true</item>
|
||||
</style>
|
||||
<style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar" />
|
||||
<style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" />
|
||||
|
||||
</resources>
|
||||
@@ -0,0 +1,50 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||
|
||||
buildscript {
|
||||
repositories {
|
||||
gradlePluginPortal()
|
||||
maven {
|
||||
url 'https://maven.google.com'
|
||||
}
|
||||
google()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:7.4.1'
|
||||
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
// in the individual module build.gradle files
|
||||
}
|
||||
}
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
gradlePluginPortal()
|
||||
maven {
|
||||
url 'https://maven.google.com'
|
||||
}
|
||||
mavenLocal()
|
||||
mavenCentral()
|
||||
google()
|
||||
}
|
||||
}
|
||||
|
||||
task clean(type: Delete) {
|
||||
delete rootProject.buildDir
|
||||
}
|
||||
Executable
+19
@@ -0,0 +1,19 @@
|
||||
#!/bin/bash
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
CURR_DIR=$(cd `dirname $0`; pwd)
|
||||
keytool -genkey -keystore $CURR_DIR/tvmrpc.keystore -alias tvmrpc -keyalg RSA -validity 10000
|
||||
Executable
+23
@@ -0,0 +1,23 @@
|
||||
#!/bin/bash
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
CURR_DIR=$(cd `dirname $0`; pwd)
|
||||
APK_DIR=$CURR_DIR/../app/build/outputs/apk/release
|
||||
UNSIGNED_APK=$APK_DIR/app-release-unsigned.apk
|
||||
SIGNED_APK=$APK_DIR/tvmrpc-release.apk
|
||||
jarsigner -verbose -keystore $CURR_DIR/tvmrpc.keystore -signedjar $SIGNED_APK $UNSIGNED_APK 'tvmrpc'
|
||||
echo $SIGNED_APK
|
||||
@@ -0,0 +1,19 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
android.useAndroidX=true
|
||||
android.enableJetifier=true
|
||||
@@ -0,0 +1,18 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
include ':app'
|
||||
@@ -0,0 +1,86 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
# ruff: noqa: F821
|
||||
"""Testcode for Android RPC.
|
||||
|
||||
To use it, start an RPC tracker with "python -m tvm.exec.rpc_tracker".
|
||||
Use the tracker's address and port when configuring the RPC app.
|
||||
Use "android" as the key if you wish to avoid modifying this script.
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
import numpy as np
|
||||
|
||||
import tvm
|
||||
from tvm import rpc, te
|
||||
from tvm.support import ndk, utils
|
||||
|
||||
# Set to be address of tvm proxy.
|
||||
tracker_host = os.environ["TVM_TRACKER_HOST"]
|
||||
tracker_port = int(os.environ["TVM_TRACKER_PORT"])
|
||||
key = "android"
|
||||
|
||||
# Change target configuration.
|
||||
# Run `adb shell cat /proc/cpuinfo` to find the arch.
|
||||
arch = "arm64"
|
||||
target = {"kind": "llvm", "mtriple": f"{arch}-linux-android"}
|
||||
|
||||
# whether enable to execute test on OpenCL target
|
||||
test_opencl = False
|
||||
# whether enable to execute test on Vulkan target
|
||||
test_vulkan = False
|
||||
|
||||
|
||||
def test_rpc_module():
|
||||
# graph
|
||||
n = tvm.runtime.convert(1024)
|
||||
A = te.placeholder((n,), name="A")
|
||||
B = te.compute(A.shape, lambda *i: A(*i) + 1.0, name="B")
|
||||
a_np = np.random.uniform(size=1024).astype(A.dtype)
|
||||
temp = utils.tempdir()
|
||||
|
||||
# Establish remote connection with target hardware
|
||||
tracker = rpc.connect_tracker(tracker_host, tracker_port)
|
||||
remote = tracker.request(key, priority=0, session_timeout=60)
|
||||
|
||||
mod = tvm.IRModule.from_expr(te.create_prim_func([A, B]).with_attr("global_symbol", "myadd"))
|
||||
sch = tvm.s_tir.Schedule(mod)
|
||||
(x,) = sch.get_loops(block=sch.get_sblock("B"))
|
||||
xo, xi = sch.split(i, [None, 32])
|
||||
sch.bind(xo, "blockIdx.x")
|
||||
sch.bind(xi, "threadIdx.x")
|
||||
|
||||
if test_opencl:
|
||||
f = tvm.compile(sch.mod, target=tvm.target.Target("opencl", host=target))
|
||||
path_dso_cl = temp.relpath("dev_lib_cl.so")
|
||||
f.export_library(path_dso_cl, fcompile=ndk.create_shared)
|
||||
|
||||
print("Run GPU(OpenCL Flavor) test ...")
|
||||
dev = remote.cl(0)
|
||||
remote.upload(path_dso_cl)
|
||||
f1 = remote.load_module("dev_lib_cl.so")
|
||||
a = tvm.runtime.tensor(a_np, dev)
|
||||
b = tvm.runtime.tensor(np.zeros(1024, dtype=A.dtype), dev)
|
||||
time_f = f1.time_evaluator(f1.entry_name, dev, number=10)
|
||||
cost = time_f(a, b).mean
|
||||
print(f"{cost:g} secs/op\n")
|
||||
np.testing.assert_equal(b.numpy(), a.numpy() + 1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
test_rpc_module()
|
||||
@@ -0,0 +1,82 @@
|
||||
cmake_policy(SET CMP0069 NEW) # suppress CMake warning about IPO
|
||||
|
||||
set(TVM_RPC_SOURCES
|
||||
main.cc
|
||||
rpc_env.cc
|
||||
rpc_server.cc
|
||||
)
|
||||
|
||||
set(TVM_RPC_LINKER_LIBS "")
|
||||
|
||||
if(WIN32)
|
||||
list(APPEND TVM_RPC_SOURCES win32_process.cc)
|
||||
endif()
|
||||
|
||||
# Set output to same directory as the other TVM libs
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
|
||||
add_executable(tvm_rpc ${TVM_RPC_SOURCES})
|
||||
|
||||
include(CheckIPOSupported)
|
||||
check_ipo_supported(RESULT result OUTPUT output)
|
||||
if(result)
|
||||
set_property(TARGET tvm_rpc PROPERTY INTERPROCEDURAL_OPTIMIZATION_RELEASE TRUE)
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
target_compile_definitions(tvm_rpc PUBLIC -DNOMINMAX)
|
||||
endif()
|
||||
|
||||
if (OS)
|
||||
if (OS STREQUAL "Linux")
|
||||
set_property(TARGET tvm_rpc PROPERTY LINK_FLAGS -lpthread)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(USE_OPENCL)
|
||||
if (ANDROID_ABI)
|
||||
if(DEFINED ENV{ANDROID_NDK_MAJOR})
|
||||
if($ENV{ANDROID_NDK_MAJOR} VERSION_LESS "23")
|
||||
set_property(TARGET tvm_rpc PROPERTY LINK_FLAGS -fuse-ld=gold)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
target_include_directories(
|
||||
tvm_rpc
|
||||
PUBLIC "../../include"
|
||||
)
|
||||
|
||||
target_link_libraries(tvm_rpc PUBLIC tvm_ffi_header)
|
||||
|
||||
if (BUILD_FOR_ANDROID AND USE_HEXAGON)
|
||||
get_hexagon_sdk_property("${USE_HEXAGON_SDK}" "${USE_HEXAGON_ARCH}"
|
||||
DSPRPC_LIB DSPRPC_LIB_DIRS
|
||||
)
|
||||
if(DSPRPC_LIB_DIRS)
|
||||
link_directories(${DSPRPC_LIB_DIRS})
|
||||
else()
|
||||
message(WARNING "Could not locate some Hexagon SDK components")
|
||||
endif()
|
||||
list(APPEND TVM_RPC_LINKER_LIBS cdsprpc log)
|
||||
endif()
|
||||
|
||||
if(BUILD_STATIC_RUNTIME)
|
||||
foreach(lib ${TVM_RUNTIME_BACKEND_LIBS})
|
||||
if(MSVC)
|
||||
list(APPEND TVM_RPC_LINKER_LIBS "/WHOLEARCHIVE:$<TARGET_FILE:${lib}>")
|
||||
elseif(APPLE)
|
||||
list(APPEND TVM_RPC_LINKER_LIBS "-Wl,-force_load,$<TARGET_FILE:${lib}>")
|
||||
else()
|
||||
list(APPEND TVM_RPC_LINKER_LIBS "-Wl,--whole-archive" "${lib}" "-Wl,--no-whole-archive")
|
||||
endif()
|
||||
endforeach()
|
||||
else()
|
||||
if(NOT MSVC AND NOT APPLE)
|
||||
list(APPEND TVM_RPC_LINKER_LIBS tvm_runtime "-Wl,--no-as-needed" ${TVM_RUNTIME_BACKEND_LIBS} "-Wl,--as-needed")
|
||||
else()
|
||||
list(APPEND TVM_RPC_LINKER_LIBS tvm_runtime ${TVM_RUNTIME_BACKEND_LIBS})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
target_link_libraries(tvm_rpc PRIVATE ${TVM_RPC_LINKER_LIBS})
|
||||
@@ -0,0 +1,83 @@
|
||||
<!--- Licensed to the Apache Software Foundation (ASF) under one -->
|
||||
<!--- or more contributor license agreements. See the NOTICE file -->
|
||||
<!--- distributed with this work for additional information -->
|
||||
<!--- regarding copyright ownership. The ASF licenses this file -->
|
||||
<!--- to you under the Apache License, Version 2.0 (the -->
|
||||
<!--- "License"); you may not use this file except in compliance -->
|
||||
<!--- with the License. You may obtain a copy of the License at -->
|
||||
|
||||
<!--- http://www.apache.org/licenses/LICENSE-2.0 -->
|
||||
|
||||
<!--- Unless required by applicable law or agreed to in writing, -->
|
||||
<!--- software distributed under the License is distributed on an -->
|
||||
<!--- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -->
|
||||
<!--- KIND, either express or implied. See the License for the -->
|
||||
<!--- specific language governing permissions and limitations -->
|
||||
<!--- under the License. -->
|
||||
|
||||
# TVM RPC Server
|
||||
This folder contains a simple recipe to make RPC server in c++.
|
||||
|
||||
## Usage (Non-Windows)
|
||||
- Configure the tvm CMake build with `config.cmake` ensuring that `USE_CPP_RPC` is set to `ON` in the config.
|
||||
- If cross compiling for Android, add the following options to the CMake config or specify them when invoking CMake:
|
||||
```
|
||||
# Whether to build the C++ RPC server binary
|
||||
set(USE_CPP_RPC ON)
|
||||
# Path to the Android NDK CMake toolchain
|
||||
set(CMAKE_TOOLCHAIN_FILE $ENV{ANDROID_NDK}/build/cmake/android.toolchain.cmake)
|
||||
# The Android ABI and platform to target
|
||||
set(ANDROID_ABI "arm64-v8a")
|
||||
set(ANDROID_PLATFORM android-28)
|
||||
```
|
||||
- Similarly, if cross compiling for embedded Linux add the following options to CMake config:
|
||||
```
|
||||
# Needed to ensure pthread is linked
|
||||
set(OS Linux)
|
||||
# Path to the desired C++ cross compiler
|
||||
set(CMAKE_CXX_COMPILER /path/to/cross/compiler/executable)
|
||||
```
|
||||
- If you need to build cpp_rpc with OpenCL support, specify variable `USE_OPENCL` in the config:
|
||||
```
|
||||
set(USE_OPENCL ON)
|
||||
```
|
||||
In this case [OpenCL-wrapper](../../src/runtime/opencl/opencl_wrapper) or OpenCL installed to your system will be used.
|
||||
When OpenCL-wrapper is used, it will dynamically load OpenCL library on the device.
|
||||
If the device doesn't have OpenCL library on it, then you'll see in the runtime that OpenCL library cannot be opened.
|
||||
|
||||
If linking against a custom device OpenCL library is needed, in the config specify the path to the OpenCL SDK containing the include/CL headers and lib/ or lib64/libOpenCL.so:
|
||||
```
|
||||
set(USE_OPENCL /path/to/opencl-sdk)
|
||||
```
|
||||
|
||||
- From within the configured tvm build directory, compile `tvm_runtime` and the `tvm_rpc` server:
|
||||
```
|
||||
cmake --build $TVM_ROOT/build --target tvm_runtime tvm_rpc -j$(nproc)
|
||||
```
|
||||
- Use `./tvm_rpc server` to start the RPC server
|
||||
|
||||
## Usage (Windows)
|
||||
- Configure the tvm CMake build with `config.cmake` ensuring that `USE_CPP_RPC` is set to `ON` in the config.
|
||||
- Install [LLVM pre-build binaries](https://releases.llvm.org/download.html), making sure to select the option to add it to the PATH.
|
||||
- Verify Python 3.6 or newer is installed and in the PATH.
|
||||
- Use `<tvm_output_dir>\tvm_rpc.exe` to start the RPC server
|
||||
|
||||
## How it works
|
||||
- The tvm runtime dll is linked along with this executable and when the RPC server starts it will load the tvm runtime library.
|
||||
|
||||
```
|
||||
Command line usage
|
||||
server - Start the server
|
||||
--host - The listen address of the server, Default=0.0.0.0 (any)
|
||||
--port - The port of the RPC server, Default=9090
|
||||
--port-end - The end search port of the RPC server, Default=9099
|
||||
--tracker - The RPC tracker address in host:port format e.g. 10.1.1.2:9190 Default=""
|
||||
--key - The key used to identify the device type in tracker. Default=""
|
||||
--custom-addr - Custom IP Address to Report to RPC Tracker. Default=""
|
||||
--silent - Whether to run in silent mode. Default=False
|
||||
Example
|
||||
./tvm_rpc server --host=0.0.0.0 --port=9090 --port-end=9099 --tracker=127.0.0.1:9190 --key=rasp
|
||||
```
|
||||
|
||||
## Note
|
||||
Currently support is only there for Linux / Android / Windows environment and proxy mode isn't supported currently.
|
||||
@@ -0,0 +1,311 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \file rpc_server.cc
|
||||
* \brief RPC Server for TVM.
|
||||
*/
|
||||
#include <csignal>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#if defined(__linux__) || defined(__ANDROID__)
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <tvm/runtime/logging.h>
|
||||
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
|
||||
#include "../../src/support/socket.h"
|
||||
#include "../../src/support/utils.h"
|
||||
#include "rpc_server.h"
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include "win32_process.h"
|
||||
#endif
|
||||
|
||||
using namespace std;
|
||||
using namespace tvm::runtime;
|
||||
using namespace tvm::support;
|
||||
|
||||
static const string kUsage =
|
||||
"Command line usage\n"
|
||||
" server - Start the server\n"
|
||||
"--host - The listen address of the server, Default=0.0.0.0 (any)\n"
|
||||
"--port - The port of the RPC server, Default=9090\n"
|
||||
"--port-end - The end search port of the RPC server, Default=9099\n"
|
||||
"--tracker - The RPC tracker address in host:port format e.g. 10.1.1.2:9190 Default=\"\"\n"
|
||||
"--key - The key used to identify the device type in tracker. Default=\"\"\n"
|
||||
"--custom-addr - Custom IP Address to Report to RPC Tracker. Default=\"\"\n"
|
||||
"--work-dir - Custom work directory. Default=\"\"\n"
|
||||
"--silent - Whether to run in silent mode. Default=False\n"
|
||||
"\n"
|
||||
" Example\n"
|
||||
" ./tvm_rpc server --host=0.0.0.0 --port=9090 --port-end=9099 "
|
||||
" --tracker=127.0.0.1:9190 --key=rasp"
|
||||
"\n";
|
||||
|
||||
/*!
|
||||
* \brief RpcServerArgs.
|
||||
* \arg host The listen address of the server, Default=0.0.0.0 (any)
|
||||
* \arg port The port of the RPC server, Default=9090
|
||||
* \arg port_end The end search port of the RPC server, Default=9099
|
||||
* \arg tracker The address of RPC tracker in host:port format e.g. 10.77.1.234:9190 Default=""
|
||||
* \arg key The key used to identify the device type in tracker. Default=""
|
||||
* \arg custom_addr Custom IP Address to Report to RPC Tracker. Default=""
|
||||
* \arg work_dir Custom work directory. Default=""
|
||||
* \arg silent Whether run in silent mode. Default=False
|
||||
*/
|
||||
struct RpcServerArgs {
|
||||
string host = "0.0.0.0";
|
||||
int port = 9090;
|
||||
int port_end = 9099;
|
||||
string tracker;
|
||||
string key;
|
||||
string custom_addr;
|
||||
string work_dir;
|
||||
bool silent = false;
|
||||
#if defined(WIN32)
|
||||
std::string mmap_path;
|
||||
#endif
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief PrintArgs print the contents of RpcServerArgs
|
||||
* \param args RpcServerArgs structure
|
||||
*/
|
||||
void PrintArgs(const RpcServerArgs& args) {
|
||||
LOG(INFO) << "host = " << args.host;
|
||||
LOG(INFO) << "port = " << args.port;
|
||||
LOG(INFO) << "port_end = " << args.port_end;
|
||||
LOG(INFO) << "tracker = " << args.tracker;
|
||||
LOG(INFO) << "key = " << args.key;
|
||||
LOG(INFO) << "custom_addr = " << args.custom_addr;
|
||||
LOG(INFO) << "work_dir = " << args.work_dir;
|
||||
LOG(INFO) << "silent = " << ((args.silent) ? ("True") : ("False"));
|
||||
}
|
||||
|
||||
#if defined(__linux__) || defined(__ANDROID__)
|
||||
/*!
|
||||
* \brief CtrlCHandler, exits if Ctrl+C is pressed
|
||||
* \param s signal
|
||||
*/
|
||||
void CtrlCHandler(int s) {
|
||||
LOG(INFO) << "\nUser pressed Ctrl+C, Exiting";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief HandleCtrlC Register for handling Ctrl+C event.
|
||||
*/
|
||||
void HandleCtrlC() {
|
||||
// Ctrl+C handler
|
||||
struct sigaction sigIntHandler;
|
||||
sigIntHandler.sa_handler = CtrlCHandler;
|
||||
sigemptyset(&sigIntHandler.sa_mask);
|
||||
sigIntHandler.sa_flags = 0;
|
||||
sigaction(SIGINT, &sigIntHandler, nullptr);
|
||||
}
|
||||
#endif
|
||||
/*!
|
||||
* \brief GetCmdOption Parse and find the command option.
|
||||
* \param argc arg counter
|
||||
* \param argv arg values
|
||||
* \param option command line option to search for.
|
||||
* \param key whether the option itself is key
|
||||
* \return value corresponding to option.
|
||||
*/
|
||||
string GetCmdOption(int argc, char* argv[], string option, bool key = false) {
|
||||
string cmd;
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
string arg = argv[i];
|
||||
if (arg.find(option) == 0) {
|
||||
if (key) {
|
||||
cmd = argv[i];
|
||||
return cmd;
|
||||
}
|
||||
// We assume "=" is the end of option.
|
||||
TVM_FFI_ICHECK_EQ(*option.rbegin(), '=');
|
||||
cmd = arg.substr(arg.find('=') + 1);
|
||||
return cmd;
|
||||
}
|
||||
}
|
||||
return cmd;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief ValidateTracker Check the tracker address format is correct and changes the format.
|
||||
* \param tracker The tracker input.
|
||||
* \return result of operation.
|
||||
*/
|
||||
bool ValidateTracker(string& tracker) {
|
||||
vector<string> list = Split(tracker, ':');
|
||||
if ((list.size() != 2) || (!ValidateIP(list[0])) || (!IsNumber(list[1]))) {
|
||||
return false;
|
||||
}
|
||||
ostringstream ss;
|
||||
ss << "('" << list[0] << "', " << list[1] << ")";
|
||||
tracker = ss.str();
|
||||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief ParseCmdArgs parses the command line arguments.
|
||||
* \param argc arg counter
|
||||
* \param argv arg values
|
||||
* \param args the output structure which holds the parsed values
|
||||
*/
|
||||
void ParseCmdArgs(int argc, char* argv[], struct RpcServerArgs& args) {
|
||||
const string silent = GetCmdOption(argc, argv, "--silent", true);
|
||||
if (!silent.empty()) {
|
||||
args.silent = true;
|
||||
}
|
||||
|
||||
const string host = GetCmdOption(argc, argv, "--host=");
|
||||
if (!host.empty()) {
|
||||
if (!ValidateIP(host)) {
|
||||
LOG(WARNING) << "Wrong host address format.";
|
||||
LOG(INFO) << kUsage;
|
||||
exit(1);
|
||||
}
|
||||
args.host = host;
|
||||
}
|
||||
|
||||
const string port = GetCmdOption(argc, argv, "--port=");
|
||||
if (!port.empty()) {
|
||||
if (!IsNumber(port) || stoi(port) > 65535) {
|
||||
LOG(WARNING) << "Wrong port number.";
|
||||
LOG(INFO) << kUsage;
|
||||
exit(1);
|
||||
}
|
||||
args.port = stoi(port);
|
||||
}
|
||||
|
||||
const string port_end = GetCmdOption(argc, argv, "--port-end=");
|
||||
if (!port_end.empty()) {
|
||||
if (!IsNumber(port_end) || stoi(port_end) > 65535) {
|
||||
LOG(WARNING) << "Wrong port-end number.";
|
||||
LOG(INFO) << kUsage;
|
||||
exit(1);
|
||||
}
|
||||
args.port_end = stoi(port_end);
|
||||
}
|
||||
|
||||
string tracker = GetCmdOption(argc, argv, "--tracker=");
|
||||
if (!tracker.empty()) {
|
||||
if (!ValidateTracker(tracker)) {
|
||||
LOG(WARNING) << "Wrong tracker address format.";
|
||||
LOG(INFO) << kUsage;
|
||||
exit(1);
|
||||
}
|
||||
args.tracker = tracker;
|
||||
}
|
||||
|
||||
const string key = GetCmdOption(argc, argv, "--key=");
|
||||
if (!key.empty()) {
|
||||
args.key = key;
|
||||
}
|
||||
|
||||
const string custom_addr = GetCmdOption(argc, argv, "--custom-addr=");
|
||||
if (!custom_addr.empty()) {
|
||||
if (!ValidateIP(custom_addr)) {
|
||||
LOG(WARNING) << "Wrong custom address format.";
|
||||
LOG(INFO) << kUsage;
|
||||
exit(1);
|
||||
}
|
||||
args.custom_addr = custom_addr;
|
||||
}
|
||||
#if defined(WIN32)
|
||||
const string mmap_path = GetCmdOption(argc, argv, "--child_proc=");
|
||||
if (!mmap_path.empty()) {
|
||||
args.mmap_path = mmap_path;
|
||||
}
|
||||
#endif
|
||||
const string work_dir = GetCmdOption(argc, argv, "--work-dir=");
|
||||
if (!work_dir.empty()) {
|
||||
args.work_dir = work_dir;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief RpcServer Starts the RPC server.
|
||||
* \param argc arg counter
|
||||
* \param argv arg values
|
||||
* \return result of operation.
|
||||
*/
|
||||
int RpcServer(int argc, char* argv[]) {
|
||||
RpcServerArgs args;
|
||||
|
||||
/* parse the command line args */
|
||||
ParseCmdArgs(argc, argv, args);
|
||||
PrintArgs(args);
|
||||
|
||||
LOG(INFO) << "Starting CPP Server, Press Ctrl+C to stop.";
|
||||
#if defined(__linux__) || defined(__ANDROID__)
|
||||
// Ctrl+C handler
|
||||
HandleCtrlC();
|
||||
#endif
|
||||
|
||||
#if defined(WIN32)
|
||||
if (!args.mmap_path.empty()) {
|
||||
int ret = 0;
|
||||
|
||||
try {
|
||||
ChildProcSocketHandler(args.mmap_path);
|
||||
} catch (const std::exception&) {
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
RPCServerCreate(args.host, args.port, args.port_end, args.tracker, args.key, args.custom_addr,
|
||||
args.work_dir, args.silent);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief main The main function.
|
||||
* \param argc arg counter
|
||||
* \param argv arg values
|
||||
* \return result of operation.
|
||||
*/
|
||||
int main(int argc, char* argv[]) {
|
||||
if (argc <= 1) {
|
||||
LOG(INFO) << kUsage;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Runs WSAStartup on Win32, no-op on POSIX
|
||||
Socket::Startup();
|
||||
#if defined(_WIN32)
|
||||
SetEnvironmentVariableA("CUDA_CACHE_DISABLE", "1");
|
||||
#endif
|
||||
|
||||
if (0 == strcmp(argv[1], "server")) {
|
||||
return RpcServer(argc, argv);
|
||||
}
|
||||
|
||||
LOG(INFO) << kUsage;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,288 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
/*!
|
||||
* \file rpc_env.cc
|
||||
* \brief Server environment of the RPC.
|
||||
*/
|
||||
#include "rpc_env.h"
|
||||
|
||||
#include <tvm/ffi/extra/module.h>
|
||||
#include <tvm/ffi/function.h>
|
||||
#include <tvm/runtime/logging.h>
|
||||
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <system_error>
|
||||
#include <vector>
|
||||
|
||||
#include "../../src/support/utils.h"
|
||||
|
||||
namespace {
|
||||
std::string GenerateUntarCommand(const std::string& tar_file, const std::string& output_dir) {
|
||||
std::string untar_cmd;
|
||||
untar_cmd.reserve(512);
|
||||
#if defined(__linux__) || defined(__ANDROID__) || defined(__APPLE__)
|
||||
untar_cmd += "tar -C ";
|
||||
untar_cmd += output_dir;
|
||||
untar_cmd += " -zxf ";
|
||||
untar_cmd += tar_file;
|
||||
#elif defined(_WIN32)
|
||||
untar_cmd += "python -m tarfile -e ";
|
||||
untar_cmd += tar_file;
|
||||
untar_cmd += " ";
|
||||
untar_cmd += output_dir;
|
||||
#endif
|
||||
return untar_cmd;
|
||||
}
|
||||
|
||||
} // Anonymous namespace
|
||||
|
||||
namespace tvm {
|
||||
namespace runtime {
|
||||
|
||||
RPCEnv::RPCEnv(const std::string& wd) {
|
||||
std::error_code ec;
|
||||
if (!wd.empty()) {
|
||||
base_ = wd + "/.cache";
|
||||
std::filesystem::create_directories(base_, ec);
|
||||
if (ec) {
|
||||
LOG(WARNING) << "Failed to create directory " << base_ << " : " << ec.message();
|
||||
}
|
||||
} else {
|
||||
#if defined(ANDROID) || defined(__ANDROID__)
|
||||
std::string pkg_name;
|
||||
if (std::ifstream cmdline("/proc/self/cmdline"); cmdline) {
|
||||
std::getline(cmdline, pkg_name, '\0');
|
||||
}
|
||||
std::string android_base_ = "/data/data/" + pkg_name + "/cache";
|
||||
// Check if application data directory exist. If not exist, usually means we run tvm_rpc from
|
||||
// adb shell terminal.
|
||||
if (!std::filesystem::is_directory(android_base_)) {
|
||||
// Tmp directory is always writable for 'shell' user.
|
||||
android_base_ = "/data/local/tmp";
|
||||
}
|
||||
base_ = android_base_ + "/rpc";
|
||||
#elif !defined(_WIN32)
|
||||
base_ = std::filesystem::current_path(ec).string() + "/rpc";
|
||||
if (ec) {
|
||||
base_ = "./rpc";
|
||||
}
|
||||
#else
|
||||
base_ = "./rpc";
|
||||
#endif
|
||||
std::filesystem::create_directories(base_, ec);
|
||||
if (ec) {
|
||||
LOG(WARNING) << "Failed to create directory " << base_ << " : " << ec.message();
|
||||
}
|
||||
}
|
||||
std::filesystem::permissions(base_, std::filesystem::perms::all,
|
||||
std::filesystem::perm_options::replace, ec);
|
||||
if (ec) {
|
||||
LOG(WARNING) << "Failed to grant permissions to " << base_ << " : " << ec.message();
|
||||
}
|
||||
|
||||
ffi::Function::SetGlobal(
|
||||
"tvm.rpc.server.workpath",
|
||||
ffi::Function::FromTyped([this](const std::string& path) { return this->GetPath(path); }));
|
||||
|
||||
ffi::Function::SetGlobal("tvm.rpc.server.listdir",
|
||||
ffi::Function::FromTyped([this](const std::string& path) {
|
||||
std::string dir = this->GetPath(path);
|
||||
std::ostringstream os;
|
||||
for (auto d : ListDir(dir)) {
|
||||
os << d << ",";
|
||||
}
|
||||
return os.str();
|
||||
}));
|
||||
|
||||
ffi::Function::SetGlobal("tvm.rpc.server.load_module",
|
||||
ffi::Function::FromTyped([this](const std::string& path) {
|
||||
std::string file_name = this->GetPath(path);
|
||||
file_name = BuildSharedLibrary(file_name);
|
||||
LOG(INFO) << "Load module from " << file_name << " ...";
|
||||
return ffi::Module::LoadFromFile(file_name);
|
||||
}));
|
||||
|
||||
ffi::Function::SetGlobal("tvm.rpc.server.download_linked_module",
|
||||
ffi::Function::FromTyped([this](const std::string& path) {
|
||||
std::string file_name = this->GetPath(path);
|
||||
file_name = BuildSharedLibrary(file_name);
|
||||
std::string bin;
|
||||
|
||||
std::ifstream fs(file_name, std::ios::in | std::ios::binary);
|
||||
TVM_FFI_ICHECK(!fs.fail()) << "Cannot open " << file_name;
|
||||
fs.seekg(0, std::ios::end);
|
||||
size_t size = static_cast<size_t>(fs.tellg());
|
||||
fs.seekg(0, std::ios::beg);
|
||||
bin.resize(size);
|
||||
fs.read(bin.data(), size);
|
||||
LOG(INFO) << "Send linked module " << file_name << " to client";
|
||||
return ffi::Bytes(bin);
|
||||
}));
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief GetPath To get the work path from packed function
|
||||
* \param file_name The file name
|
||||
* \return The full path of file.
|
||||
*/
|
||||
std::string RPCEnv::GetPath(const std::string& file_name) const {
|
||||
// we assume file_name starts with "/" means file_name is the exact path
|
||||
// and does not create /.rpc/
|
||||
return !file_name.empty() && file_name[0] == '/' ? file_name : base_ + "/" + file_name;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Remove The RPC Environment cleanup function
|
||||
*/
|
||||
void RPCEnv::CleanUp() const {
|
||||
std::error_code ec;
|
||||
std::filesystem::remove_all(base_, ec);
|
||||
if (ec) {
|
||||
LOG(WARNING) << "Cleanup " << base_ << " failed: " << ec.message();
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief ListDir get the list of files in a directory
|
||||
* \param dirname The root directory name
|
||||
* \return vector Files in directory.
|
||||
*/
|
||||
std::vector<std::string> ListDir(const std::string& dirname) {
|
||||
std::error_code ec;
|
||||
std::vector<std::string> vec;
|
||||
auto iter = std::filesystem::directory_iterator(dirname, ec);
|
||||
if (ec) {
|
||||
if (ec == std::errc::no_such_file_or_directory) return vec;
|
||||
TVM_FFI_THROW(InternalError) << "ListDir " << dirname << " error: " << ec.message();
|
||||
}
|
||||
for (const auto& entry : iter) {
|
||||
vec.push_back(entry.path().generic_string());
|
||||
}
|
||||
return vec;
|
||||
}
|
||||
|
||||
#if defined(__linux__) || defined(__ANDROID__) || defined(__APPLE__)
|
||||
/*!
|
||||
* \brief LinuxShared Creates a linux shared library
|
||||
* \param output The output file name
|
||||
* \param files The files for building
|
||||
* \param options The compiler options
|
||||
* \param cc The compiler
|
||||
*/
|
||||
void LinuxShared(const std::string output, const std::vector<std::string>& files,
|
||||
std::string options = "", std::string cc = "g++") {
|
||||
std::string cmd = cc;
|
||||
cmd += " -shared -fPIC ";
|
||||
cmd += " -o " + output;
|
||||
for (auto f = files.begin(); f != files.end(); ++f) {
|
||||
cmd += " " + *f;
|
||||
}
|
||||
cmd += " " + options;
|
||||
std::string err_msg;
|
||||
auto executed_status = support::Execute(cmd, &err_msg);
|
||||
if (executed_status) {
|
||||
TVM_FFI_THROW(InternalError) << err_msg;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
/*!
|
||||
* \brief WindowsShared Creates a Windows shared library
|
||||
* \param output The output file name
|
||||
* \param files The files for building
|
||||
* \param options The compiler options
|
||||
* \param cc The compiler
|
||||
*/
|
||||
void WindowsShared(const std::string& output, const std::vector<std::string>& files,
|
||||
const std::string& options = "", const std::string& cc = "clang") {
|
||||
std::string cmd = cc;
|
||||
cmd += " -O2 -flto=full -fuse-ld=lld-link -shared ";
|
||||
cmd += " -o " + output;
|
||||
for (const auto& file : files) {
|
||||
cmd += " " + file;
|
||||
}
|
||||
cmd += " " + options;
|
||||
std::string err_msg;
|
||||
const auto executed_status = support::Execute(cmd, &err_msg);
|
||||
if (executed_status) {
|
||||
TVM_FFI_THROW(InternalError) << err_msg;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*!
|
||||
* \brief CreateShared Creates a shared library
|
||||
* \param output The output file name
|
||||
* \param files The files for building
|
||||
*/
|
||||
void CreateShared(const std::string& output, const std::vector<std::string>& files) {
|
||||
#if defined(__linux__) || defined(__ANDROID__) || defined(__APPLE__)
|
||||
LinuxShared(output, files);
|
||||
#elif defined(_WIN32)
|
||||
WindowsShared(output, files);
|
||||
#else
|
||||
TVM_FFI_THROW(InternalError) << "Operating system not supported";
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string BuildSharedLibrary(std::string file) {
|
||||
if (support::EndsWith(file, ".so") || support::EndsWith(file, ".dll") ||
|
||||
support::EndsWith(file, ".dylib")) {
|
||||
return file;
|
||||
}
|
||||
|
||||
std::string file_name = file + ".so";
|
||||
if (support::EndsWith(file, ".o")) {
|
||||
CreateShared(file_name, {file});
|
||||
} else if (support::EndsWith(file, ".tar")) {
|
||||
const std::string tmp_dir = "./rpc/tmp/";
|
||||
std::error_code ec;
|
||||
std::filesystem::create_directories(tmp_dir, ec);
|
||||
if (ec) {
|
||||
LOG(WARNING) << "Failed to create directory " << tmp_dir << " : " << ec.message();
|
||||
}
|
||||
std::filesystem::permissions(tmp_dir, std::filesystem::perms::all,
|
||||
std::filesystem::perm_options::replace, ec);
|
||||
if (ec) {
|
||||
LOG(WARNING) << "Failed to grant permissions to " << tmp_dir << " : " << ec.message();
|
||||
}
|
||||
|
||||
const std::string cmd = GenerateUntarCommand(file, tmp_dir);
|
||||
|
||||
std::string err_msg;
|
||||
const int executed_status = support::Execute(cmd, &err_msg);
|
||||
if (executed_status) {
|
||||
TVM_FFI_THROW(InternalError) << err_msg;
|
||||
}
|
||||
CreateShared(file_name, ListDir(tmp_dir));
|
||||
std::filesystem::remove_all(tmp_dir, ec);
|
||||
if (ec) {
|
||||
LOG(WARNING) << "Remove " << tmp_dir << " failed: " << ec.message();
|
||||
}
|
||||
} else {
|
||||
file_name = file;
|
||||
}
|
||||
return file_name;
|
||||
}
|
||||
|
||||
} // namespace runtime
|
||||
} // namespace tvm
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \file rpc_env.h
|
||||
* \brief Server environment of the RPC.
|
||||
*/
|
||||
#ifndef TVM_APPS_CPP_RPC_ENV_H_
|
||||
#define TVM_APPS_CPP_RPC_ENV_H_
|
||||
|
||||
#include <tvm/ffi/function.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace tvm {
|
||||
namespace runtime {
|
||||
|
||||
/*!
|
||||
* \brief ListDir Get the list of files in a directory
|
||||
* \param dirname The root directory name
|
||||
* \return vector Files in directory.
|
||||
*/
|
||||
std::vector<std::string> ListDir(const std::string& dirname);
|
||||
|
||||
/*!
|
||||
* \brief build a shared library if necessary
|
||||
*
|
||||
* This function will automatically call
|
||||
* cc.create_shared if the path is in format .o or .tar
|
||||
* High level handling for .o and .tar file.
|
||||
* We support this to be consistent with RPC module load.
|
||||
* \param file_in The input file path.
|
||||
*
|
||||
* \return The name of the shared library.
|
||||
*/
|
||||
std::string BuildSharedLibrary(std::string file_in);
|
||||
|
||||
/*!
|
||||
* \brief RPCEnv The RPC Environment parameters for c++ rpc server
|
||||
*/
|
||||
struct RPCEnv {
|
||||
public:
|
||||
/*!
|
||||
* \brief Constructor Init The RPC Environment initialize function
|
||||
*/
|
||||
RPCEnv(const std::string& word_dir = "");
|
||||
/*!
|
||||
* \brief GetPath To get the workpath from packed function
|
||||
* \param name The file name
|
||||
* \return The full path of file.
|
||||
*/
|
||||
std::string GetPath(const std::string& file_name) const;
|
||||
/*!
|
||||
* \brief The RPC Environment cleanup function
|
||||
*/
|
||||
void CleanUp() const;
|
||||
|
||||
private:
|
||||
/*!
|
||||
* \brief Holds the environment path.
|
||||
*/
|
||||
std::string base_;
|
||||
}; // RPCEnv
|
||||
|
||||
} // namespace runtime
|
||||
} // namespace tvm
|
||||
#endif // TVM_APPS_CPP_RPC_ENV_H_
|
||||
@@ -0,0 +1,394 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \file rpc_server.cc
|
||||
* \brief RPC Server implementation.
|
||||
*/
|
||||
#include <tvm/ffi/function.h>
|
||||
#include <tvm/ffi/reflection/registry.h>
|
||||
#if defined(__linux__) || defined(__ANDROID__) || defined(__APPLE__)
|
||||
#include <signal.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/wait.h>
|
||||
#endif
|
||||
#include <chrono>
|
||||
#include <future>
|
||||
#include <iostream>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <utility>
|
||||
|
||||
#include "../../src/runtime/rpc/rpc_endpoint.h"
|
||||
#include "../../src/runtime/rpc/rpc_socket_impl.h"
|
||||
#include "../../src/support/socket.h"
|
||||
#include "rpc_env.h"
|
||||
#include "rpc_server.h"
|
||||
#include "rpc_tracker_client.h"
|
||||
#if defined(_WIN32)
|
||||
#include "win32_process.h"
|
||||
#endif
|
||||
|
||||
using namespace std::chrono;
|
||||
|
||||
namespace tvm {
|
||||
namespace runtime {
|
||||
|
||||
#ifdef __ANDROID__
|
||||
static std::string getNextString(std::stringstream* iss) {
|
||||
std::string str = iss->str();
|
||||
size_t start = iss->tellg();
|
||||
size_t len = str.size();
|
||||
// Skip leading spaces.
|
||||
while (start < len && isspace(str[start])) start++;
|
||||
|
||||
size_t end = start;
|
||||
while (end < len && !isspace(str[end])) end++;
|
||||
|
||||
iss->seekg(end);
|
||||
return str.substr(start, end - start);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*!
|
||||
* \brief RPCServer RPC Server class.
|
||||
*
|
||||
* \param host The listen address of the server, Default=0.0.0.0 (any)
|
||||
*
|
||||
* \param port_search_start The low end of the search range for an
|
||||
* available port for the RPC, Default=9090
|
||||
*
|
||||
* \param port_search_end The high search the search range for an
|
||||
* available port for the RPC, Default=9099
|
||||
*
|
||||
* \param tracker The address of RPC tracker in host:port format
|
||||
* (e.g. "10.77.1.234:9190")
|
||||
*
|
||||
* \param key The key used to identify the device type in tracker.
|
||||
*
|
||||
* \param custom_addr Custom IP Address to Report to RPC Tracker.
|
||||
*/
|
||||
class RPCServer {
|
||||
public:
|
||||
/*!
|
||||
* \brief Constructor.
|
||||
*/
|
||||
RPCServer(std::string host, int port_search_start, int port_search_end, std::string tracker_addr,
|
||||
std::string key, std::string custom_addr, std::string work_dir)
|
||||
: host_(std::move(host)),
|
||||
port_search_start_(port_search_start),
|
||||
my_port_(0),
|
||||
port_search_end_(port_search_end),
|
||||
tracker_addr_(std::move(tracker_addr)),
|
||||
key_(std::move(key)),
|
||||
custom_addr_(std::move(custom_addr)),
|
||||
work_dir_(std::move(work_dir)) {}
|
||||
|
||||
/*!
|
||||
* \brief Destructor.
|
||||
*/
|
||||
~RPCServer() {
|
||||
try {
|
||||
// Free the resources
|
||||
tracker_sock_.Close();
|
||||
listen_sock_.Close();
|
||||
} catch (...) {
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Start Creates the RPC listen process and execution.
|
||||
*/
|
||||
void Start() {
|
||||
listen_sock_.Create();
|
||||
my_port_ = listen_sock_.TryBindHost(host_, port_search_start_, port_search_end_);
|
||||
LOG(INFO) << "Bind to " << host_ << ":" << my_port_;
|
||||
listen_sock_.Listen(1);
|
||||
std::future<void> proc(std::async(std::launch::async, &RPCServer::ListenLoopProc, this));
|
||||
proc.get();
|
||||
// Close the listen socket
|
||||
listen_sock_.Close();
|
||||
}
|
||||
|
||||
private:
|
||||
/*!
|
||||
* \brief ListenLoopProc The listen process.
|
||||
*/
|
||||
void ListenLoopProc() {
|
||||
TrackerClient tracker(tracker_addr_, key_, custom_addr_, my_port_);
|
||||
while (true) {
|
||||
support::TCPSocket conn;
|
||||
support::SockAddr addr("0.0.0.0", 0);
|
||||
std::string opts;
|
||||
try {
|
||||
// step 1: setup tracker and report to tracker
|
||||
tracker.TryConnect();
|
||||
// step 2: wait for in-coming connections
|
||||
AcceptConnection(&tracker, &conn, &addr, &opts);
|
||||
} catch (const char* msg) {
|
||||
LOG(WARNING) << "Socket exception: " << msg;
|
||||
// close tracker resource
|
||||
tracker.Close();
|
||||
continue;
|
||||
} catch (const std::exception& e) {
|
||||
// close tracker resource
|
||||
tracker.Close();
|
||||
LOG(WARNING) << "Exception standard: " << e.what();
|
||||
continue;
|
||||
}
|
||||
|
||||
int timeout = GetTimeOutFromOpts(opts);
|
||||
#if defined(__linux__) || defined(__ANDROID__) || defined(__APPLE__)
|
||||
// step 3: serving
|
||||
if (timeout != 0) {
|
||||
const pid_t worker_pid = fork();
|
||||
if (worker_pid == 0) {
|
||||
// Worker process
|
||||
ServerLoopProc(conn, addr, work_dir_);
|
||||
_exit(0);
|
||||
}
|
||||
|
||||
int status = 0;
|
||||
bool timed_out = false;
|
||||
auto start_timer = std::chrono::steady_clock::now();
|
||||
while (true) {
|
||||
// Check worker pid (non-blocking)
|
||||
int ret = waitpid(worker_pid, &status, WNOHANG);
|
||||
if (ret == worker_pid) {
|
||||
break;
|
||||
} else if (ret == -1) {
|
||||
if (errno == EINTR) continue;
|
||||
break;
|
||||
}
|
||||
// Check worker timeout
|
||||
if (std::chrono::steady_clock::now() - start_timer >= std::chrono::seconds(timeout)) {
|
||||
timed_out = true;
|
||||
kill(worker_pid, SIGTERM);
|
||||
waitpid(worker_pid, &status, 0);
|
||||
break;
|
||||
}
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
||||
}
|
||||
|
||||
// Logging.
|
||||
if (timed_out) {
|
||||
LOG(INFO) << "Child pid=" << worker_pid << " killed"
|
||||
<< " (timeout = " << timeout << " sec)"
|
||||
<< ", status = " << status;
|
||||
} else {
|
||||
LOG(INFO) << "Child pid=" << worker_pid << " finished"
|
||||
<< ", status = " << status;
|
||||
}
|
||||
} else {
|
||||
auto pid = fork();
|
||||
if (pid == 0) {
|
||||
ServerLoopProc(conn, addr, work_dir_);
|
||||
_exit(0);
|
||||
}
|
||||
// Wait for the result
|
||||
int status = 0;
|
||||
wait(&status);
|
||||
LOG(INFO) << "Child pid=" << pid << " exited, status =" << status;
|
||||
}
|
||||
#elif defined(WIN32)
|
||||
auto start_time = high_resolution_clock::now();
|
||||
try {
|
||||
SpawnRPCChild(conn.sockfd, seconds(timeout));
|
||||
} catch (const std::exception&) {
|
||||
}
|
||||
auto dur = high_resolution_clock::now() - start_time;
|
||||
|
||||
LOG(INFO) << "Serve Time " << duration_cast<milliseconds>(dur).count() << "ms";
|
||||
#else
|
||||
LOG(WARNING) << "Unknown platform. It is not known how to bring up the subprocess."
|
||||
<< " RPC will be launched in the main thread.";
|
||||
ServerLoopProc(conn, addr, work_dir_);
|
||||
#endif
|
||||
// close from our side.
|
||||
LOG(INFO) << "End session with " << addr.AsString();
|
||||
conn.Close();
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief AcceptConnection Accepts the RPC Server connection.
|
||||
* \param tracker Tracker details.
|
||||
* \param conn_sock New connection information.
|
||||
* \param addr New connection address information.
|
||||
* \param opts Parsed options for socket
|
||||
* \param ping_period Timeout for select call waiting
|
||||
*/
|
||||
void AcceptConnection(TrackerClient* tracker, support::TCPSocket* conn_sock,
|
||||
support::SockAddr* addr, std::string* opts, int ping_period = 2) {
|
||||
std::set<std::string> old_keyset;
|
||||
std::string matchkey;
|
||||
|
||||
// Report resource to tracker and get key
|
||||
tracker->ReportResourceAndGetKey(my_port_, &matchkey);
|
||||
|
||||
while (true) {
|
||||
tracker->WaitConnectionAndUpdateKey(listen_sock_, my_port_, ping_period, &matchkey);
|
||||
support::TCPSocket conn = listen_sock_.Accept(addr);
|
||||
|
||||
int code = kRPCMagic;
|
||||
TVM_FFI_ICHECK_EQ(conn.RecvAll(&code, sizeof(code)), sizeof(code));
|
||||
if (code != kRPCMagic) {
|
||||
conn.Close();
|
||||
TVM_FFI_THROW(InternalError) << "Client connected is not TVM RPC server";
|
||||
continue;
|
||||
}
|
||||
|
||||
int keylen = 0;
|
||||
TVM_FFI_ICHECK_EQ(conn.RecvAll(&keylen, sizeof(keylen)), sizeof(keylen));
|
||||
|
||||
const char* CLIENT_HEADER = "client:";
|
||||
const char* SERVER_HEADER = "server:";
|
||||
std::string expect_header = CLIENT_HEADER + matchkey;
|
||||
std::string server_key = SERVER_HEADER + key_;
|
||||
if (size_t(keylen) < expect_header.length()) {
|
||||
conn.Close();
|
||||
LOG(INFO) << "Wrong client header length";
|
||||
continue;
|
||||
}
|
||||
|
||||
TVM_FFI_ICHECK_NE(keylen, 0);
|
||||
std::string remote_key;
|
||||
remote_key.resize(keylen);
|
||||
TVM_FFI_ICHECK_EQ(conn.RecvAll(&remote_key[0], keylen), keylen);
|
||||
|
||||
std::stringstream ssin(remote_key);
|
||||
std::string arg0;
|
||||
#ifndef __ANDROID__
|
||||
ssin >> arg0;
|
||||
#else
|
||||
arg0 = getNextString(&ssin);
|
||||
#endif
|
||||
|
||||
if (arg0 != expect_header) {
|
||||
code = kRPCMismatch;
|
||||
TVM_FFI_ICHECK_EQ(conn.SendAll(&code, sizeof(code)), sizeof(code));
|
||||
conn.Close();
|
||||
LOG(WARNING) << "Mismatch key from" << addr->AsString();
|
||||
continue;
|
||||
} else {
|
||||
code = kRPCSuccess;
|
||||
TVM_FFI_ICHECK_EQ(conn.SendAll(&code, sizeof(code)), sizeof(code));
|
||||
keylen = int(server_key.length());
|
||||
TVM_FFI_ICHECK_EQ(conn.SendAll(&keylen, sizeof(keylen)), sizeof(keylen));
|
||||
TVM_FFI_ICHECK_EQ(conn.SendAll(server_key.c_str(), keylen), keylen);
|
||||
LOG(INFO) << "New session from " << addr->AsString();
|
||||
#ifndef __ANDROID__
|
||||
ssin >> *opts;
|
||||
#else
|
||||
*opts = getNextString(&ssin);
|
||||
#endif
|
||||
*conn_sock = conn;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief ServerLoopProc The Server loop process.
|
||||
* \param sock The socket information
|
||||
* \param addr The socket address information
|
||||
*/
|
||||
static void ServerLoopProc(support::TCPSocket sock, support::SockAddr addr,
|
||||
std::string work_dir) {
|
||||
// Server loop
|
||||
const auto s_time = std::chrono::high_resolution_clock::now();
|
||||
const auto env = RPCEnv(work_dir);
|
||||
RPCServerLoop(int(sock.sockfd));
|
||||
const auto e_time = std::chrono::high_resolution_clock::now();
|
||||
std::chrono::duration<double> elapsed = e_time - s_time;
|
||||
LOG(INFO) << "Finished serving " << addr.AsString() << " after " << elapsed.count() << " sec";
|
||||
env.CleanUp();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief GetTimeOutFromOpts Parse and get the timeout option.
|
||||
* \param opts The option string
|
||||
*/
|
||||
int GetTimeOutFromOpts(const std::string& opts) const {
|
||||
const std::string option = "-timeout=";
|
||||
|
||||
size_t pos = opts.rfind(option);
|
||||
if (pos != std::string::npos) {
|
||||
const std::string cmd = opts.substr(pos + option.size());
|
||||
TVM_FFI_ICHECK(support::IsNumber(cmd)) << "Timeout is not valid";
|
||||
return std::stoi(cmd);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string host_;
|
||||
int port_search_start_;
|
||||
int my_port_;
|
||||
int port_search_end_;
|
||||
std::string tracker_addr_;
|
||||
std::string key_;
|
||||
std::string custom_addr_;
|
||||
std::string work_dir_;
|
||||
support::TCPSocket listen_sock_;
|
||||
support::TCPSocket tracker_sock_;
|
||||
};
|
||||
|
||||
#if defined(WIN32)
|
||||
/*!
|
||||
* \brief ServerLoopFromChild The Server loop process.
|
||||
* \param socket The socket information
|
||||
*/
|
||||
void ServerLoopFromChild(SOCKET socket) {
|
||||
// Server loop
|
||||
tvm::support::TCPSocket sock(socket);
|
||||
const auto env = RPCEnv();
|
||||
RPCServerLoop(int(sock.sockfd));
|
||||
|
||||
sock.Close();
|
||||
env.CleanUp();
|
||||
}
|
||||
#endif
|
||||
|
||||
/*!
|
||||
* \brief RPCServerCreate Creates the RPC Server.
|
||||
* \param host The listen address of the server, Default=0.0.0.0 (any)
|
||||
* \param port The port of the RPC server, Default=9090
|
||||
* \param port_end The end search port of the RPC server, Default=9099
|
||||
* \param tracker_addr The address of RPC tracker in host:port format e.g. 10.77.1.234:9190
|
||||
* Default="" \param key The key used to identify the device type in tracker. Default="" \param
|
||||
* custom_addr Custom IP Address to Report to RPC Tracker. Default="" \param silent Whether run in
|
||||
* silent mode. Default=True
|
||||
*/
|
||||
void RPCServerCreate(std::string host, int port, int port_end, std::string tracker_addr,
|
||||
std::string key, std::string custom_addr, std::string work_dir, bool silent) {
|
||||
if (silent) {
|
||||
}
|
||||
// Start the rpc server
|
||||
RPCServer rpc(std::move(host), port, port_end, std::move(tracker_addr), std::move(key),
|
||||
std::move(custom_addr), std::move(work_dir));
|
||||
rpc.Start();
|
||||
}
|
||||
|
||||
TVM_FFI_STATIC_INIT_BLOCK() {
|
||||
namespace refl = tvm::ffi::reflection;
|
||||
refl::GlobalDef().def("rpc.ServerCreate", RPCServerCreate);
|
||||
}
|
||||
} // namespace runtime
|
||||
} // namespace tvm
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \file rpc_server.h
|
||||
* \brief RPC Server implementation.
|
||||
*/
|
||||
#ifndef TVM_APPS_CPP_RPC_SERVER_H_
|
||||
#define TVM_APPS_CPP_RPC_SERVER_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "tvm/runtime/base.h"
|
||||
|
||||
namespace tvm {
|
||||
namespace runtime {
|
||||
|
||||
#if defined(WIN32)
|
||||
/*!
|
||||
* \brief ServerLoopFromChild The Server loop process.
|
||||
* \param sock The socket information
|
||||
* \param addr The socket address information
|
||||
*/
|
||||
void ServerLoopFromChild(SOCKET socket);
|
||||
#endif
|
||||
|
||||
/*!
|
||||
* \brief RPCServerCreate Creates the RPC Server.
|
||||
* \param host The listen address of the server, Default=0.0.0.0 (any)
|
||||
* \param port The port of the RPC server, Default=9090
|
||||
* \param port_end The end search port of the RPC server, Default=9099
|
||||
* \param tracker The address of RPC tracker in host:port format e.g. 10.77.1.234:9190 Default=""
|
||||
* \param key The key used to identify the device type in tracker. Default=""
|
||||
* \param custom_addr Custom IP Address to Report to RPC Tracker. Default=""
|
||||
* \param work_dir Custom work directory. Default=""
|
||||
* \param silent Whether run in silent mode. Default=True
|
||||
*/
|
||||
void RPCServerCreate(std::string host = "", int port = 9090, int port_end = 9099,
|
||||
std::string tracker_addr = "", std::string key = "",
|
||||
std::string custom_addr = "", std::string work_dir = "", bool silent = true);
|
||||
} // namespace runtime
|
||||
} // namespace tvm
|
||||
#endif // TVM_APPS_CPP_RPC_SERVER_H_
|
||||
@@ -0,0 +1,248 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \file rpc_tracker_client.h
|
||||
* \brief RPC Tracker client to report resources.
|
||||
*/
|
||||
#ifndef TVM_APPS_CPP_RPC_TRACKER_CLIENT_H_
|
||||
#define TVM_APPS_CPP_RPC_TRACKER_CLIENT_H_
|
||||
|
||||
#include <chrono>
|
||||
#include <iostream>
|
||||
#include <random>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "../../src/runtime/rpc/rpc_endpoint.h"
|
||||
#include "../../src/support/socket.h"
|
||||
|
||||
namespace tvm {
|
||||
namespace runtime {
|
||||
|
||||
/*!
|
||||
* \brief TrackerClient Tracker client class.
|
||||
* \param tracker The address of RPC tracker in host:port format e.g. 10.77.1.234:9190 Default=""
|
||||
* \param key The key used to identify the device type in tracker. Default=""
|
||||
* \param custom_addr Custom IP Address to Report to RPC Tracker. Default=""
|
||||
*/
|
||||
class TrackerClient {
|
||||
public:
|
||||
/*!
|
||||
* \brief Constructor.
|
||||
*/
|
||||
TrackerClient(const std::string& tracker_addr, const std::string& key,
|
||||
const std::string& custom_addr, int port)
|
||||
: tracker_addr_(tracker_addr),
|
||||
key_(key),
|
||||
custom_addr_(custom_addr),
|
||||
port_(port),
|
||||
gen_(std::random_device{}()),
|
||||
dis_(0.0, 1.0) {
|
||||
if (custom_addr_.empty()) {
|
||||
custom_addr_ = "null";
|
||||
} else {
|
||||
// Since custom_addr_ can be either the json value null which is not surrounded by quotes
|
||||
// or a string containing the custom value which json does required to be quoted then we
|
||||
// need to set custom_addr_ to be a string containing the quotes here.
|
||||
custom_addr_ = "\"" + custom_addr_ + "\"";
|
||||
}
|
||||
}
|
||||
/*!
|
||||
* \brief Destructor.
|
||||
*/
|
||||
~TrackerClient() {
|
||||
// Free the resources
|
||||
Close();
|
||||
}
|
||||
/*!
|
||||
* \brief IsValid Check tracker is valid.
|
||||
*/
|
||||
bool IsValid() { return (!tracker_addr_.empty() && !tracker_sock_.IsClosed()); }
|
||||
/*!
|
||||
* \brief TryConnect Connect to tracker if the tracker address is valid.
|
||||
*/
|
||||
void TryConnect() {
|
||||
if (!tracker_addr_.empty() && (tracker_sock_.IsClosed())) {
|
||||
tracker_sock_ = ConnectWithRetry();
|
||||
|
||||
int code = kRPCTrackerMagic;
|
||||
TVM_FFI_ICHECK_EQ(tracker_sock_.SendAll(&code, sizeof(code)), sizeof(code));
|
||||
TVM_FFI_ICHECK_EQ(tracker_sock_.RecvAll(&code, sizeof(code)), sizeof(code));
|
||||
TVM_FFI_ICHECK_EQ(code, kRPCTrackerMagic) << tracker_addr_.c_str() << " is not RPC Tracker";
|
||||
|
||||
std::ostringstream ss;
|
||||
ss << "[" << static_cast<int>(TrackerCode::kUpdateInfo) << ", {\"key\": \"server:" << key_
|
||||
<< "\", \"addr\": [" << custom_addr_ << ", \"" << port_ << "\"]}]";
|
||||
tracker_sock_.SendBytes(ss.str());
|
||||
|
||||
// Receive status and validate
|
||||
std::string remote_status = tracker_sock_.RecvBytes();
|
||||
TVM_FFI_ICHECK_EQ(std::stoi(remote_status), static_cast<int>(TrackerCode::kSuccess));
|
||||
}
|
||||
}
|
||||
/*!
|
||||
* \brief Close Clean up tracker resources.
|
||||
*/
|
||||
void Close() {
|
||||
// close tracker resource
|
||||
if (!tracker_sock_.IsClosed()) {
|
||||
tracker_sock_.Close();
|
||||
}
|
||||
}
|
||||
/*!
|
||||
* \brief ReportResourceAndGetKey Report resource to tracker.
|
||||
* \param port listening port.
|
||||
* \param matchkey Random match key output.
|
||||
*/
|
||||
void ReportResourceAndGetKey(int port, std::string* matchkey) {
|
||||
if (!tracker_sock_.IsClosed()) {
|
||||
*matchkey = RandomKey(key_ + ":", old_keyset_);
|
||||
|
||||
std::ostringstream ss;
|
||||
ss << "[" << static_cast<int>(TrackerCode::kPut) << ", \"" << key_ << "\", [" << port
|
||||
<< ", \"" << *matchkey << "\"], " << custom_addr_ << "]";
|
||||
|
||||
tracker_sock_.SendBytes(ss.str());
|
||||
|
||||
// Receive status and validate
|
||||
std::string remote_status = tracker_sock_.RecvBytes();
|
||||
TVM_FFI_ICHECK_EQ(std::stoi(remote_status), static_cast<int>(TrackerCode::kSuccess));
|
||||
} else {
|
||||
*matchkey = key_;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief ReportResourceAndGetKey Report resource to tracker.
|
||||
* \param listen_sock Listen socket details for select.
|
||||
* \param port listening port.
|
||||
* \param ping_period Select wait time.
|
||||
* \param matchkey Random match key output.
|
||||
*/
|
||||
void WaitConnectionAndUpdateKey(support::TCPSocket listen_sock, int port, int ping_period,
|
||||
std::string* matchkey) {
|
||||
int unmatch_period_count = 0;
|
||||
int unmatch_timeout = 4;
|
||||
while (true) {
|
||||
if (!tracker_sock_.IsClosed()) {
|
||||
support::PollHelper poller;
|
||||
poller.WatchRead(listen_sock.sockfd);
|
||||
poller.Poll(ping_period * 1000);
|
||||
if (!poller.CheckRead(listen_sock.sockfd)) {
|
||||
std::ostringstream ss;
|
||||
ss << "[" << int(TrackerCode::kGetPendingMatchKeys) << "]";
|
||||
tracker_sock_.SendBytes(ss.str());
|
||||
|
||||
// Receive status and validate
|
||||
std::string pending_keys = tracker_sock_.RecvBytes();
|
||||
old_keyset_.insert(*matchkey);
|
||||
|
||||
// if match key not in pending key set
|
||||
// it means the key is acquired by a client but not used.
|
||||
if (pending_keys.find(*matchkey) == std::string::npos) {
|
||||
unmatch_period_count += 1;
|
||||
} else {
|
||||
unmatch_period_count = 0;
|
||||
}
|
||||
// regenerate match key if key is acquired but not used for a while
|
||||
if (unmatch_period_count * ping_period > unmatch_timeout + ping_period) {
|
||||
LOG(INFO) << "no incoming connections, regenerate key ...";
|
||||
|
||||
*matchkey = RandomKey(key_ + ":", old_keyset_);
|
||||
|
||||
std::ostringstream ss;
|
||||
ss << "[" << static_cast<int>(TrackerCode::kPut) << ", \"" << key_ << "\", [" << port
|
||||
<< ", \"" << *matchkey << "\"], " << custom_addr_ << "]";
|
||||
tracker_sock_.SendBytes(ss.str());
|
||||
|
||||
std::string remote_status = tracker_sock_.RecvBytes();
|
||||
TVM_FFI_ICHECK_EQ(std::stoi(remote_status), static_cast<int>(TrackerCode::kSuccess));
|
||||
unmatch_period_count = 0;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
/*!
|
||||
* \brief Connect to a RPC address with retry.
|
||||
This function is only reliable to short period of server restart.
|
||||
* \param timeout Timeout during retry
|
||||
* \param retry_period Number of seconds before we retry again.
|
||||
* \return TCPSocket The socket information if connect is success.
|
||||
*/
|
||||
support::TCPSocket ConnectWithRetry(int timeout = 60, int retry_period = 5) {
|
||||
auto tbegin = std::chrono::system_clock::now();
|
||||
while (true) {
|
||||
support::SockAddr addr(tracker_addr_);
|
||||
support::TCPSocket sock;
|
||||
sock.Create();
|
||||
if (sock.Connect(addr)) {
|
||||
LOG(INFO) << "Connected to tracker " << addr.AsString();
|
||||
return sock;
|
||||
}
|
||||
|
||||
auto period = (std::chrono::duration_cast<std::chrono::seconds>(
|
||||
std::chrono::system_clock::now() - tbegin))
|
||||
.count();
|
||||
TVM_FFI_ICHECK(period < timeout) << "Failed to connect to tracker " << addr.AsString();
|
||||
LOG(WARNING) << "Cannot connect to tracker " << addr.AsString() << " retry in "
|
||||
<< retry_period << " seconds.";
|
||||
std::this_thread::sleep_for(std::chrono::seconds(retry_period));
|
||||
}
|
||||
}
|
||||
/*!
|
||||
* \brief Random Generate a random number between 0 and 1.
|
||||
* \return random float value.
|
||||
*/
|
||||
float Random() { return dis_(gen_); }
|
||||
/*!
|
||||
* \brief Generate a random key.
|
||||
* \param prefix The string prefix.
|
||||
* \return cmap The conflict map set.
|
||||
*/
|
||||
std::string RandomKey(const std::string& prefix, const std::set<std::string>& cmap) {
|
||||
if (!cmap.empty()) {
|
||||
while (true) {
|
||||
std::string key = prefix + std::to_string(Random());
|
||||
if (cmap.find(key) == cmap.end()) {
|
||||
return key;
|
||||
}
|
||||
}
|
||||
}
|
||||
return prefix + std::to_string(Random());
|
||||
}
|
||||
|
||||
std::string tracker_addr_;
|
||||
std::string key_;
|
||||
std::string custom_addr_;
|
||||
int port_;
|
||||
support::TCPSocket tracker_sock_;
|
||||
std::set<std::string> old_keyset_;
|
||||
std::mt19937 gen_;
|
||||
std::uniform_real_distribution<float> dis_;
|
||||
};
|
||||
} // namespace runtime
|
||||
} // namespace tvm
|
||||
#endif // TVM_APPS_CPP_RPC_TRACKER_CLIENT_H_
|
||||
@@ -0,0 +1,262 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
#include "win32_process.h"
|
||||
|
||||
#include <conio.h>
|
||||
#include <tvm/runtime/logging.h>
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
|
||||
#include <cstdio>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
#include "rpc_server.h"
|
||||
|
||||
using namespace std::chrono;
|
||||
using namespace tvm::runtime;
|
||||
|
||||
namespace {
|
||||
// The prefix path for the memory mapped file used to store IPC information
|
||||
const std::string kMemoryMapPrefix = "/MAPPED_FILE/TVM_RPC";
|
||||
// Used to construct unique names for named resources in the parent process
|
||||
const std::string kParent = "parent";
|
||||
// Used to construct unique names for named resources in the child process
|
||||
const std::string kChild = "child";
|
||||
// The timeout of the WIN32 events, in the parent and the child
|
||||
const milliseconds kEventTimeout(2000);
|
||||
|
||||
// Used to create unique WIN32 mmap paths and event names
|
||||
int child_counter_ = 0;
|
||||
|
||||
/*!
|
||||
* \brief HandleDeleter Deleter for UniqueHandle smart pointer
|
||||
* \param handle The WIN32 HANDLE to manage
|
||||
*/
|
||||
struct HandleDeleter {
|
||||
void operator()(HANDLE handle) const {
|
||||
if (handle != INVALID_HANDLE_VALUE && handle != nullptr) {
|
||||
CloseHandle(handle);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief UniqueHandle Smart pointer to manage a WIN32 HANDLE
|
||||
*/
|
||||
using UniqueHandle = std::unique_ptr<void, HandleDeleter>;
|
||||
|
||||
/*!
|
||||
* \brief MakeUniqueHandle Helper method to construct a UniqueHandle
|
||||
* \param handle The WIN32 HANDLE to manage
|
||||
*/
|
||||
UniqueHandle MakeUniqueHandle(HANDLE handle) {
|
||||
if (handle == INVALID_HANDLE_VALUE || handle == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return UniqueHandle(handle);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief GetSocket Gets the socket info from the parent process and duplicates the socket
|
||||
* \param mmap_path The path to the memory mapped info set by the parent
|
||||
*/
|
||||
SOCKET GetSocket(const std::string& mmap_path) {
|
||||
WSAPROTOCOL_INFO protocol_info;
|
||||
|
||||
const std::string parent_event_name = mmap_path + kParent;
|
||||
const std::string child_event_name = mmap_path + kChild;
|
||||
|
||||
// Open the events
|
||||
UniqueHandle parent_file_mapping_event;
|
||||
if ((parent_file_mapping_event = MakeUniqueHandle(
|
||||
OpenEventA(SYNCHRONIZE, false, parent_event_name.c_str()))) == nullptr) {
|
||||
TVM_FFI_THROW(InternalError) << "OpenEvent() failed: " << GetLastError();
|
||||
}
|
||||
|
||||
UniqueHandle child_file_mapping_event;
|
||||
if ((child_file_mapping_event = MakeUniqueHandle(
|
||||
OpenEventA(EVENT_MODIFY_STATE, false, child_event_name.c_str()))) == nullptr) {
|
||||
TVM_FFI_THROW(InternalError) << "OpenEvent() failed: " << GetLastError();
|
||||
}
|
||||
|
||||
// Wait for the parent to set the event, notifying WSAPROTOCOL_INFO is ready to be read
|
||||
if (WaitForSingleObject(parent_file_mapping_event.get(), uint32_t(kEventTimeout.count())) !=
|
||||
WAIT_OBJECT_0) {
|
||||
TVM_FFI_THROW(InternalError) << "WaitForSingleObject() failed: " << GetLastError();
|
||||
}
|
||||
|
||||
const UniqueHandle file_map =
|
||||
MakeUniqueHandle(OpenFileMappingA(FILE_MAP_READ | FILE_MAP_WRITE, false, mmap_path.c_str()));
|
||||
if (!file_map) {
|
||||
LOG(INFO) << "CreateFileMapping() failed: " << GetLastError();
|
||||
}
|
||||
|
||||
void* map_view = MapViewOfFile(file_map.get(), FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0);
|
||||
|
||||
SOCKET sock_duplicated = INVALID_SOCKET;
|
||||
|
||||
if (map_view != nullptr) {
|
||||
memcpy(&protocol_info, map_view, sizeof(WSAPROTOCOL_INFO));
|
||||
UnmapViewOfFile(map_view);
|
||||
|
||||
// Creates the duplicate socket, that was created in the parent
|
||||
sock_duplicated =
|
||||
WSASocket(FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO, &protocol_info, 0, 0);
|
||||
|
||||
// Let the parent know we are finished duplicating the socket
|
||||
SetEvent(child_file_mapping_event.get());
|
||||
} else {
|
||||
TVM_FFI_THROW(InternalError) << "MapViewOfFile() failed: " << GetLastError();
|
||||
}
|
||||
|
||||
return sock_duplicated;
|
||||
}
|
||||
} // Anonymous namespace
|
||||
|
||||
namespace tvm {
|
||||
namespace runtime {
|
||||
/*!
|
||||
* \brief SpawnRPCChild Spawns a child process with a given timeout to run
|
||||
* \param fd The client socket to duplicate in the child
|
||||
* \param timeout The time in seconds to wait for the child to complete before termination
|
||||
*/
|
||||
void SpawnRPCChild(SOCKET fd, seconds timeout) {
|
||||
STARTUPINFOA startup_info;
|
||||
|
||||
memset(&startup_info, 0, sizeof(startup_info));
|
||||
startup_info.cb = sizeof(startup_info);
|
||||
|
||||
std::string file_map_path = kMemoryMapPrefix + std::to_string(child_counter_++);
|
||||
|
||||
const std::string parent_event_name = file_map_path + kParent;
|
||||
const std::string child_event_name = file_map_path + kChild;
|
||||
|
||||
// Create an event to let the child know the socket info was set to the mmap file
|
||||
UniqueHandle parent_file_mapping_event;
|
||||
if ((parent_file_mapping_event = MakeUniqueHandle(
|
||||
CreateEventA(nullptr, true, false, parent_event_name.c_str()))) == nullptr) {
|
||||
TVM_FFI_THROW(InternalError) << "CreateEvent for parent file mapping failed";
|
||||
}
|
||||
|
||||
UniqueHandle child_file_mapping_event;
|
||||
// An event to let the parent know the socket info was read from the mmap file
|
||||
if ((child_file_mapping_event = MakeUniqueHandle(
|
||||
CreateEventA(nullptr, true, false, child_event_name.c_str()))) == nullptr) {
|
||||
TVM_FFI_THROW(InternalError) << "CreateEvent for child file mapping failed";
|
||||
}
|
||||
|
||||
char current_executable[MAX_PATH];
|
||||
|
||||
// Get the full path of the current executable
|
||||
GetModuleFileNameA(nullptr, current_executable, MAX_PATH);
|
||||
|
||||
std::string child_command_line = current_executable;
|
||||
child_command_line += " server --child_proc=";
|
||||
child_command_line += file_map_path;
|
||||
|
||||
// CreateProcessA requires a non const char*, so we copy our std::string
|
||||
auto command_line_ptr = std::make_unique<char[]>(child_command_line.size() + 1);
|
||||
strcpy(command_line_ptr.get(), child_command_line.c_str());
|
||||
|
||||
PROCESS_INFORMATION child_process_info;
|
||||
if (CreateProcessA(nullptr, command_line_ptr.get(), nullptr, nullptr, false, CREATE_NO_WINDOW,
|
||||
nullptr, nullptr, &startup_info, &child_process_info)) {
|
||||
// Child process and thread handles must be closed, so wrapped in RAII
|
||||
auto child_process_handle = MakeUniqueHandle(child_process_info.hProcess);
|
||||
auto child_process_thread_handle = MakeUniqueHandle(child_process_info.hThread);
|
||||
|
||||
WSAPROTOCOL_INFO protocol_info;
|
||||
// Get info needed to duplicate the socket
|
||||
if (WSADuplicateSocket(fd, child_process_info.dwProcessId, &protocol_info) == SOCKET_ERROR) {
|
||||
TVM_FFI_THROW(InternalError) << "WSADuplicateSocket(): failed. Error =" << WSAGetLastError();
|
||||
}
|
||||
|
||||
// Create a mmap file to store the info needed for duplicating the SOCKET in the child proc
|
||||
UniqueHandle file_map =
|
||||
MakeUniqueHandle(CreateFileMappingA(INVALID_HANDLE_VALUE, nullptr, PAGE_READWRITE, 0,
|
||||
sizeof(WSAPROTOCOL_INFO), file_map_path.c_str()));
|
||||
if (!file_map) {
|
||||
LOG(INFO) << "CreateFileMapping() failed: " << GetLastError();
|
||||
}
|
||||
|
||||
if (GetLastError() == ERROR_ALREADY_EXISTS) {
|
||||
TVM_FFI_THROW(InternalError) << "CreateFileMapping(): mapping file already exists";
|
||||
} else {
|
||||
void* map_view = MapViewOfFile(file_map.get(), FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0);
|
||||
|
||||
if (map_view != nullptr) {
|
||||
memcpy(map_view, &protocol_info, sizeof(WSAPROTOCOL_INFO));
|
||||
UnmapViewOfFile(map_view);
|
||||
|
||||
// Let child proc know the mmap file is ready to be read
|
||||
SetEvent(parent_file_mapping_event.get());
|
||||
|
||||
// Wait for the child to finish reading mmap file
|
||||
if (WaitForSingleObject(child_file_mapping_event.get(), uint32_t(kEventTimeout.count())) !=
|
||||
WAIT_OBJECT_0) {
|
||||
TerminateProcess(child_process_handle.get(), 0);
|
||||
TVM_FFI_THROW(InternalError)
|
||||
<< "WaitForSingleObject for child file mapping timed out. Terminating child "
|
||||
"process.";
|
||||
}
|
||||
} else {
|
||||
TerminateProcess(child_process_handle.get(), 0);
|
||||
TVM_FFI_THROW(InternalError) << "MapViewOfFile() failed: " << GetLastError();
|
||||
}
|
||||
}
|
||||
|
||||
const DWORD process_timeout =
|
||||
timeout.count() ? uint32_t(duration_cast<milliseconds>(timeout).count()) : INFINITE;
|
||||
|
||||
// Wait for child process to exit, or hit configured timeout
|
||||
if (WaitForSingleObject(child_process_handle.get(), process_timeout) != WAIT_OBJECT_0) {
|
||||
LOG(INFO) << "Child process timeout. Terminating.";
|
||||
TerminateProcess(child_process_handle.get(), 0);
|
||||
}
|
||||
} else {
|
||||
LOG(INFO) << "Create child process failed: " << GetLastError();
|
||||
}
|
||||
}
|
||||
/*!
|
||||
* \brief ChildProcSocketHandler Ran from the child process and runs server to handle the client
|
||||
* socket \param mmap_path The memory mapped file path that will contain the information to
|
||||
* duplicate the client socket from the parent
|
||||
*/
|
||||
void ChildProcSocketHandler(const std::string& mmap_path) {
|
||||
SOCKET socket;
|
||||
|
||||
// Set high thread priority to avoid the thread scheduler from
|
||||
// interfering with any measurements in the RPC server.
|
||||
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
|
||||
|
||||
if ((socket = GetSocket(mmap_path)) != INVALID_SOCKET) {
|
||||
tvm::runtime::ServerLoopFromChild(socket);
|
||||
} else {
|
||||
TVM_FFI_THROW(InternalError) << "GetSocket() failed";
|
||||
}
|
||||
}
|
||||
} // namespace runtime
|
||||
} // namespace tvm
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \file win32_process.h
|
||||
* \brief Win32 process code to mimic a POSIX fork()
|
||||
*/
|
||||
#ifndef TVM_APPS_CPP_RPC_WIN32_PROCESS_H_
|
||||
#define TVM_APPS_CPP_RPC_WIN32_PROCESS_H_
|
||||
|
||||
#include <chrono>
|
||||
#include <string>
|
||||
|
||||
#include "../../src/support/socket.h"
|
||||
|
||||
namespace tvm {
|
||||
namespace runtime {
|
||||
/*!
|
||||
* \brief SpawnRPCChild Spawns a child process with a given timeout to run
|
||||
* \param fd The client socket to duplicate in the child
|
||||
* \param timeout The time in seconds to wait for the child to complete before termination
|
||||
*/
|
||||
void SpawnRPCChild(SOCKET fd, std::chrono::seconds timeout);
|
||||
/*!
|
||||
* \brief ChildProcSocketHandler Ran from the child process and runs server to handle the client
|
||||
* socket \param mmap_path The memory mapped file path that will contain the information to
|
||||
* duplicate the client socket from the parent
|
||||
*/
|
||||
void ChildProcSocketHandler(const std::string& mmap_path);
|
||||
} // namespace runtime
|
||||
} // namespace tvm
|
||||
#endif // TVM_APPS_CPP_RPC_WIN32_PROCESS_H_
|
||||
@@ -0,0 +1 @@
|
||||
rpc_config.txt
|
||||
@@ -0,0 +1,82 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
include(ExternalProject)
|
||||
|
||||
# Check if xcodebuild tool is available and configured.
|
||||
# Otherwise will skip all iOS specific targets.
|
||||
execute_process(COMMAND xcodebuild -version
|
||||
RESULT_VARIABLE XCBUILD_AVAILABLE
|
||||
OUTPUT_QUIET
|
||||
ERROR_QUIET
|
||||
)
|
||||
|
||||
if (NOT XCBUILD_AVAILABLE EQUAL 0)
|
||||
message(WARNING
|
||||
"The build tool xcodebuild is not properly configured. Please install Xcode app and specify "
|
||||
"path to it via DEVELOPER_DIR env var or \"sudo xcode-select -switch <path-to-xcode-dev-dir>\".\n"
|
||||
"iOS RPC application target is switched off."
|
||||
)
|
||||
return()
|
||||
endif()
|
||||
|
||||
# External project with custom mach-o dynamic loader
|
||||
# It is required to load unsigned shared modules on real iOS devices
|
||||
ExternalProject_Add(custom_dso_loader
|
||||
GIT_REPOSITORY https://github.com/octoml/macho-dyld.git
|
||||
GIT_TAG d1f7032e7882bc060b49a4fb058f50a23668b074
|
||||
PREFIX custom_dso_loader
|
||||
LOG_DOWNLOAD TRUE
|
||||
LOG_CONFIGURE TRUE
|
||||
CMAKE_ARGS
|
||||
-DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR> # to install into local build dir
|
||||
-DCMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS}
|
||||
-DCMAKE_SYSTEM_NAME=${CMAKE_SYSTEM_NAME}
|
||||
-DCMAKE_SYSTEM_VERSION=${CMAKE_SYSTEM_VERSION}
|
||||
-DCMAKE_OSX_SYSROOT=${CMAKE_OSX_SYSROOT}
|
||||
-DCMAKE_OSX_ARCHITECTURES=${CMAKE_OSX_ARCHITECTURES}
|
||||
-DCMAKE_OSX_DEPLOYMENT_TARGET=${CMAKE_OSX_DEPLOYMENT_TARGET}
|
||||
-DCMAKE_BUILD_WITH_INSTALL_NAME_DIR=${CMAKE_BUILD_WITH_INSTALL_NAME_DIR}
|
||||
)
|
||||
|
||||
if(NOT CMAKE_IOS_RPC_BUNDLE)
|
||||
set(CMAKE_IOS_RPC_BUNDLE org.apache.tvmrpc)
|
||||
endif()
|
||||
|
||||
# iOS RPC Xcode project wrapper to integrate into CMake
|
||||
ExternalProject_Add(ios_rpc
|
||||
PREFIX ios_rpc
|
||||
DEPENDS custom_dso_loader tvm_runtime
|
||||
SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}
|
||||
CONFIGURE_COMMAND ""
|
||||
INSTALL_COMMAND ""
|
||||
BUILD_COMMAND xcodebuild
|
||||
-target tvmrpc
|
||||
-configuration ${CMAKE_BUILD_TYPE}
|
||||
-project <SOURCE_DIR>/tvmrpc.xcodeproj
|
||||
-sdk ${CMAKE_OSX_SYSROOT}
|
||||
-arch ${CMAKE_OSX_ARCHITECTURES}
|
||||
-hideShellScriptEnvironment
|
||||
-allowProvisioningUpdates
|
||||
build
|
||||
SYMROOT=<BINARY_DIR>
|
||||
IPHONEOS_DEPLOYMENT_TARGET=${CMAKE_OSX_DEPLOYMENT_TARGET}
|
||||
DEVELOPMENT_TEAM=${CMAKE_XCODE_ATTRIBUTE_DEVELOPMENT_TEAM}
|
||||
TVM_BUILD_DIR=${CMAKE_BINARY_DIR}
|
||||
USE_CUSTOM_DSO_LOADER=1
|
||||
PRODUCT_BUNDLE_IDENTIFIER=${CMAKE_IOS_RPC_BUNDLE}
|
||||
)
|
||||
@@ -0,0 +1,256 @@
|
||||
<!--- Licensed to the Apache Software Foundation (ASF) under one -->
|
||||
<!--- or more contributor license agreements. See the NOTICE file -->
|
||||
<!--- distributed with this work for additional information -->
|
||||
<!--- regarding copyright ownership. The ASF licenses this file -->
|
||||
<!--- to you under the Apache License, Version 2.0 (the -->
|
||||
<!--- "License"); you may not use this file except in compliance -->
|
||||
<!--- with the License. You may obtain a copy of the License at -->
|
||||
|
||||
<!--- http://www.apache.org/licenses/LICENSE-2.0 -->
|
||||
|
||||
<!--- Unless required by applicable law or agreed to in writing, -->
|
||||
<!--- software distributed under the License is distributed on an -->
|
||||
<!--- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -->
|
||||
<!--- KIND, either express or implied. See the License for the -->
|
||||
<!--- specific language governing permissions and limitations -->
|
||||
<!--- under the License. -->
|
||||
|
||||
# iOS TVM RPC
|
||||
|
||||
This folder contains iOS RPC app that allows us to launch an rpc server on a iOS
|
||||
device. You will need XCode and an iOS device to use this.
|
||||
|
||||
## Table of Contents
|
||||
* [Building](#building)
|
||||
* [Building TVM runtime and custom DSO loader plugin](#building-tvm-runtime-and-custom-dso-loader-plugin)
|
||||
* [Building iOS TVM RPC application](#building-ios-tvm-rpc-application)
|
||||
* [Workflow](#workflow)
|
||||
* [Standalone RPC](#standalone-rpc)
|
||||
* [iOS RPC App with proxy](#ios-rpc-app-with-proxy)
|
||||
* [iOS RPC App with tracker](#ios-rpc-app-with-tracker)
|
||||
* [Communication without Wi-Fi and speed up in case of slow Wi-Fi](#communication-without-wi-fi-and-speed-up-in-case-of-slow-wi-fi)
|
||||
|
||||
## Building
|
||||
### Building TVM runtime and custom DSO loader plugin
|
||||
While iOS platform itself doesn't allow us to run an unsigned binary, there is a
|
||||
partial ability to run JIT code on real iOS devices. While application is
|
||||
running under debug session, system allows allocating memory with write and
|
||||
execute permissions (a debugger requirement). So we can use this feature to
|
||||
implement the `tvm.rpc.server.load_module` PackedFunc, used to load code over
|
||||
RPC. For this purpose we use custom version of `dlopen` function which doesn't
|
||||
check signature and permissions for module loading. This custom `dlopen`
|
||||
mechanic is integrated into TVM RPC as plugin and registered to execution only
|
||||
inside iOS RPC application.
|
||||
|
||||
The custom implementation of `dlopen` and other functions from `dlfcn.h` header are placed in separate repository,
|
||||
and will be downloaded automatically during CMake build for iOS.
|
||||
|
||||
Also, it is necessary to build `libtvm_runtime.dylib` for our iOS device. The
|
||||
iOS TVM RPC application will be linked with this library.
|
||||
|
||||
Run the build using the following commands:
|
||||
```shell
|
||||
export DEVELOPER_DIR=/Applications/Xcode.app # iOS SDK is part of Xcode bundle. Have to set it as default Dev Env
|
||||
cmake ..
|
||||
-DCMAKE_BUILD_TYPE=Debug
|
||||
-DCMAKE_SYSTEM_NAME=iOS
|
||||
-DCMAKE_SYSTEM_VERSION=14.0
|
||||
-DCMAKE_OSX_SYSROOT=iphoneos
|
||||
-DCMAKE_OSX_ARCHITECTURES=arm64
|
||||
-DCMAKE_OSX_DEPLOYMENT_TARGET=14.0
|
||||
-DCMAKE_BUILD_WITH_INSTALL_NAME_DIR=ON
|
||||
-DUSE_IOS_RPC=ON # to enable build iOS RPC application from TVM project tree
|
||||
-DUSE_METAL=ON # to enable Metal runtime
|
||||
|
||||
cmake --build . --target custom_dso_loader tvm_runtime
|
||||
```
|
||||
|
||||
### Building iOS TVM RPC application
|
||||
Before start, please run [init_proj.py](./init_proj.py) to update XCode developer metadata:
|
||||
```shell
|
||||
python3 init_proj.py --team_id XXXXXXXXXX --tvm_build_dir "/path/to/tvm/ios/build/folder"
|
||||
```
|
||||
You can get value of your `team_id` in the following ways:
|
||||
- **You have registered Apple Developer Profile**. In this case you developer
|
||||
Team ID available at https://developer.apple.com/account/#/membership
|
||||
- You are using your local developer profile. In this case, leave `XXXXXXXXXX`
|
||||
in the command instead of substituting a Team ID. Then open `tvmrpc.xcodeproj`
|
||||
by using XCode, click on the project name (`tvmrpc`) on the left panel. Then
|
||||
select target `tvmrpc`. At the bottom of this panel go to `Signing &
|
||||
Capabilities` tab and in the field `Team` select your local developer profile
|
||||
(`Your Name (Personal Team)`).
|
||||
|
||||
On the first run of the application you may see message `Could not launch
|
||||
"tvmrpc"` in the XCode and message `Untrusted Developer` on your device. In
|
||||
this case it will be necessary to check the certificate. Open
|
||||
`Settings -> General -> Device Management -> Apple Development: <your_email>
|
||||
-> Trust "Apple Development: <your_email>"` and click `Trust`. After than you
|
||||
should rerun your application in the XCode.
|
||||
|
||||
After this step, open `tvmrpc.xcodeproj` by using XCode, build the App and
|
||||
install the App on the phone.
|
||||
|
||||
## Workflow
|
||||
Due to security restriction of iOS10. We cannot upload dynamic libraries to the
|
||||
App and load it from sandbox. Instead, we need to build a list of libraries,
|
||||
pack them into the app bundle, launch the RPC server and connect to test the
|
||||
bundled libraries. For more on the approach we use to work around this
|
||||
limitation, please take a look into section
|
||||
[Building TVM runtime and custom DSO loader integration](#building-tvm-runtime-and-custom-DSO-loader-plugin).
|
||||
|
||||
The test script [tests/ios_rpc_test.py](tests/ios_rpc_test.py) and
|
||||
[tests/ios_rpc_mobilenet.py](tests/ios_rpc_mobilenet.py) are good templates for
|
||||
demonstrating the workflow.
|
||||
|
||||
We have three different modes for iOS RPC server:
|
||||
- [Standalone RPC](#standalone-rpc): In this mode RPC server open port on the device and listening. Then
|
||||
client connects to the server directly without any mediators.
|
||||
- [iOS RPC application with Proxy](#ios-rpc-app-with-proxy): RPC server and RPC client communicates through
|
||||
`rpc_proxy`. The RPC server on iOS device notify `rpc_proxy` which was run on
|
||||
host machine about itself and wait for incoming connections. Communications
|
||||
between client and server works through `rpc_proxy`.
|
||||
- [iOS RPC application with Tracker](#ios-rpc-app-with-tracker): RPC server registered in the `rpc_tracker`
|
||||
and client connects to the RPC server through `rpc_tracker`.
|
||||
|
||||
### Standalone RPC
|
||||
Start RPC server on your iOS device:
|
||||
- Push on the `Connect` button.
|
||||
|
||||
After that you supposed to see something like this in the app on the device:
|
||||
```
|
||||
IP: <device_ip>
|
||||
Port: <rpc_server_port>
|
||||
```
|
||||
|
||||
Printed `IP` is the IP address of your device and `PORT` is the number of port
|
||||
which was open for RPC connection. Next you should use them for connect your RPC
|
||||
client to the server.
|
||||
|
||||
Let's check that direct RPC connection works and we can upload a library with
|
||||
model and execute it on the device. For this purpose we will use
|
||||
[ios_rpc_test.py](tests/ios_rpc_test.py). Run it:
|
||||
```shell
|
||||
python3 tests/ios_rpc_test.py --host <device_ip> --port <rpc_server_port> --mode "standalone"
|
||||
```
|
||||
This will compile TVM IR to shared libraries (CPU and Metal) and run vector
|
||||
addition on your iOS device. You are supposed to see something like this:
|
||||
```
|
||||
Metal: 0.000338692 secs/op
|
||||
CPU: 0.000219308 secs/op
|
||||
```
|
||||
|
||||
### iOS RPC App with proxy
|
||||
Start the RPC proxy by running in a terminal:
|
||||
```shell
|
||||
python3 -m tvm.exec.rpc_proxy --host 0.0.0.0 --port 9090
|
||||
```
|
||||
|
||||
On success, you should see something like this:
|
||||
```
|
||||
INFO:root:RPCProxy: client port bind to 0.0.0.0:9090
|
||||
INFO:root:RPCProxy: Websock port bind to 8888
|
||||
```
|
||||
Connect your iOS device to the RPC proxy via the iOS TVM RPC application. Set
|
||||
the `Address` and `Port` fields to the address and port of the RPC tracker
|
||||
respectively. Select mode `Proxy` and push `Connect` button. In success the
|
||||
text on the button will be changed to `Disconnect` and `Disconnected` in the top
|
||||
of the screen will be changed to `Connected`.
|
||||
On RPC proxy side you can see the next message in a log:
|
||||
```
|
||||
INFO:root:Handler ready TCPSocketProxy:<iPhone IP address>:server:iphone
|
||||
```
|
||||
Then we can check that RPC connection works and we can upload a library with
|
||||
model and execute it on the target device. For this purpose we will use
|
||||
[ios_rpc_test.py](tests/ios_rpc_test.py). Run it:
|
||||
```shell
|
||||
python3 tests/ios_rpc_test.py --host <host_ip_address> --port 9090 --mode "proxy"
|
||||
```
|
||||
The output should be the same as it was in previous section.
|
||||
|
||||
### iOS RPC App with tracker
|
||||
First start an RPC tracker using
|
||||
```shell
|
||||
python3 -m tvm.exec.rpc_tracker --host 0.0.0.0 --port 9190
|
||||
```
|
||||
On success, you should see something like this:
|
||||
```
|
||||
INFO:RPCTracker:bind to 0.0.0.0:9190
|
||||
```
|
||||
Connect your iOS device to the RPC tracker via the iOS TVM RPC applcation. Set
|
||||
the `Address` and `Port` fields to the address and port of the RPC tracker
|
||||
respectively. Select mode `Tracker` and push `Connect` button. In success the
|
||||
text on the button will be changed to `Disconnect` and `Disconnected` in the top
|
||||
of the screen will be changed to `Connected`. On the host side you can check the
|
||||
connect by the following command:
|
||||
```shell
|
||||
python3 -m tvm.exec.query_rpc_tracker --port 9190
|
||||
```
|
||||
You are supposed to see something like this:
|
||||
```
|
||||
Tracker address 127.0.0.1:9190
|
||||
|
||||
Server List
|
||||
----------------------------
|
||||
server-address key
|
||||
----------------------------
|
||||
192.168.1.57:9190 server:iphone
|
||||
----------------------------
|
||||
|
||||
Queue Status
|
||||
------------------------------
|
||||
key total free pending
|
||||
------------------------------
|
||||
iphone 1 1 0
|
||||
------------------------------
|
||||
```
|
||||
|
||||
Then we can check that RPC connection works and we can upload a library with
|
||||
model and execute it on the target device. For this purpose we will use
|
||||
[ios_rpc_test.py](tests/ios_rpc_test.py). Run it:
|
||||
```shell
|
||||
python3 tests/ios_rpc_test.py --host <host_ip_address> --port 9190 --mode "tracker"
|
||||
```
|
||||
The output will be the same as in section
|
||||
[Standalone RPC](#standalone-rpc).
|
||||
|
||||
## Communication without Wi-Fi and speed up in case of slow Wi-Fi
|
||||
Connection to the RPC server through `usbmux` can be used then you have slow,
|
||||
unstable or don't have any Wi-Fi connection. `usbmux` is used for binding local
|
||||
TCP port to port on the device and transfer packages between these ports by USB
|
||||
cable.
|
||||
|
||||
First of all you should install `usbmux` to your system. You can do it with
|
||||
brew:
|
||||
```shell
|
||||
brew install usbmuxd
|
||||
```
|
||||
After that you can use `iproxy` program for binding ports. You can use it for
|
||||
all described workflows. Let's take a look how it works for
|
||||
[Standalone RPC](#standalone-rpc).
|
||||
|
||||
First, start RPC server on your iOS device. You may see something like this in
|
||||
the app on the device:
|
||||
```
|
||||
IP: unknown
|
||||
Port: <rpc_server_port>
|
||||
```
|
||||
**Note.** Here `IP: unknown` because there was no Internet connection on the iOS
|
||||
device.
|
||||
Printed `Port` is the port of the RPC server on your iOS device. We will use it
|
||||
in binding ports. Run `iproxy`, specify local port which should be used for
|
||||
communication with device and the printed port on the device:
|
||||
```shell
|
||||
iproxy <local_port>:<rpc_server_port>
|
||||
```
|
||||
After this command you should see something like this:
|
||||
```
|
||||
Creating listening port <local_port> for device port <rpc_server_port>
|
||||
waiting for connection
|
||||
```
|
||||
Now we can check that RPC connection through `usbmux` works and we can upload a
|
||||
library with model and execute it on the device. For this purpose we will use
|
||||
[ios_rpc_test.py](tests/ios_rpc_test.py). Run it:
|
||||
```shell
|
||||
python3 tests/ios_rpc_test.py --host 0.0.0.0 --port <local_port> --mode standalone
|
||||
```
|
||||
The output should be the same as in all previous runs.
|
||||
@@ -0,0 +1,56 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
import argparse
|
||||
|
||||
default_team_id = "3FR42MXLK9"
|
||||
default_tvm_build_dir = "path-to-tvm-ios-build-folder"
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Update tvmrpc.xcodeproj\
|
||||
developer information"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--team_id",
|
||||
type=str,
|
||||
required=True,
|
||||
help=f"Apple Developer Team ID.\n\
|
||||
Can be found here:\n\
|
||||
\n\
|
||||
https://developer.apple.com/account/#/membership\n\
|
||||
(example: {default_team_id})",
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"--tvm_build_dir",
|
||||
type=str,
|
||||
required=True,
|
||||
help="Path to directory with libtvm_runtime.dylib",
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
team_id = args.team_id
|
||||
tvm_build_dir = args.tvm_build_dir
|
||||
|
||||
fi = open("tvmrpc.xcodeproj/project.pbxproj")
|
||||
proj_config = fi.read()
|
||||
fi.close()
|
||||
|
||||
proj_config = proj_config.replace(default_team_id, team_id)
|
||||
proj_config = proj_config.replace(default_tvm_build_dir, tvm_build_dir)
|
||||
fo = open("tvmrpc.xcodeproj/project.pbxproj", "w")
|
||||
fo.write(proj_config)
|
||||
fo.close()
|
||||
@@ -0,0 +1,97 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
"""Testcode for iOS RPC.
|
||||
|
||||
To use it, start a rpc proxy with "python -m tvm.exec.rpc_proxy".
|
||||
And configure the proxy host field as commented.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
|
||||
import numpy as np
|
||||
|
||||
import tvm
|
||||
from tvm import rpc, te
|
||||
from tvm.support import utils, xcode
|
||||
|
||||
# Change target configuration, this is setting for iphone6s
|
||||
arch = "arm64"
|
||||
sdk = "iphoneos"
|
||||
target = {"kind": "llvm", "mtriple": f"{arch}-apple-darwin"}
|
||||
|
||||
MODES = {"proxy": rpc.connect, "tracker": rpc.connect_tracker, "standalone": rpc.connect}
|
||||
|
||||
|
||||
# override metal compiler to compile to iphone
|
||||
@tvm.register_global_func("tvm_callback_metal_compile")
|
||||
def compile_metal(src, target):
|
||||
return xcode.compile_metal(src, sdk=sdk)
|
||||
|
||||
|
||||
def test_rpc_module(host, port, key, mode):
|
||||
# graph
|
||||
n = tvm.runtime.convert(1024)
|
||||
A = te.placeholder((n,), name="A")
|
||||
B = te.compute(A.shape, lambda *i: A(*i) + 1.0, name="B")
|
||||
temp = utils.tempdir()
|
||||
mod = tvm.IRModule.from_expr(te.create_prim_func([A, B]).with_attr("global_symbol", "myadd"))
|
||||
sch = tvm.s_tir.Schedule(mod)
|
||||
(i,) = sch.get_loops(block=sch.get_sblock("B"))
|
||||
i0, i1 = sch.split(i, [None, 32])
|
||||
sch.bind(i0, "blockIdx.x")
|
||||
sch.bind(i1, "threadIdx.x")
|
||||
|
||||
# Build the dynamic lib.
|
||||
# If we don't want to do metal and only use cpu, just set target to be target
|
||||
f = tvm.compile(sch.mod, target=tvm.target.Target("metal", host=target))
|
||||
path_dso1 = temp.relpath("dev_lib.dylib")
|
||||
f.export_library(path_dso1, fcompile=xcode.create_dylib, arch=arch, sdk=sdk)
|
||||
|
||||
# connect to the proxy
|
||||
if mode == "tracker":
|
||||
remote = MODES[mode](host, port).request(key)
|
||||
else:
|
||||
remote = MODES[mode](host, port, key=key)
|
||||
remote.upload(path_dso1)
|
||||
dev = remote.metal(0)
|
||||
f1 = remote.load_module("dev_lib.dylib")
|
||||
a_np = np.random.uniform(size=1024).astype(A.dtype)
|
||||
a = tvm.runtime.tensor(a_np, dev)
|
||||
b = tvm.runtime.tensor(np.zeros(1024, dtype=A.dtype), dev)
|
||||
time_f = f1.time_evaluator(f1.entry_name, dev, number=10)
|
||||
cost = time_f(a, b).mean
|
||||
print(f"Metal: {cost:g} secs/op")
|
||||
np.testing.assert_equal(b.numpy(), a.numpy() + 1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(description="Demo app demonstrates how ios_rpc works.")
|
||||
parser.add_argument("--host", required=True, type=str, help="Address of rpc server")
|
||||
parser.add_argument("--port", type=int, default=9090, help="rpc port (default: 9090)")
|
||||
parser.add_argument("--key", type=str, default="iphone", help="device key (default: iphone)")
|
||||
parser.add_argument(
|
||||
"--mode",
|
||||
type=str,
|
||||
default="tracker",
|
||||
help="type of RPC connection (default: tracker), possible values: {}".format(
|
||||
", ".join(MODES.keys())
|
||||
),
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
assert args.mode in MODES.keys()
|
||||
test_rpc_module(args.host, args.port, args.key, args.mode)
|
||||
@@ -0,0 +1,442 @@
|
||||
// !$*UTF8*$!
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
{
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 46;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
016B19C22657B390002E1719 /* RPCServer.mm in Sources */ = {isa = PBXBuildFile; fileRef = 016B19C12657B390002E1719 /* RPCServer.mm */; };
|
||||
01A1DB432652CBA700655BBC /* RPCArgs.mm in Sources */ = {isa = PBXBuildFile; fileRef = 01A1DB412652CBA700655BBC /* RPCArgs.mm */; };
|
||||
01A9B7B3265BD1FD000D092F /* libtvm_runtime.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 01A9B7B2265BD1FD000D092F /* libtvm_runtime.dylib */; };
|
||||
01A9B7B8265BD307000D092F /* libtvm_runtime.dylib in Embed Libraries */ = {isa = PBXBuildFile; fileRef = 01A9B7B2265BD1FD000D092F /* libtvm_runtime.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
|
||||
C02637501F1C25E8007247A9 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = C026374F1F1C25E8007247A9 /* main.m */; };
|
||||
C02637531F1C25E8007247A9 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = C02637521F1C25E8007247A9 /* AppDelegate.m */; };
|
||||
C02637591F1C25E8007247A9 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C02637571F1C25E8007247A9 /* Main.storyboard */; };
|
||||
C026375B1F1C25E8007247A9 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C026375A1F1C25E8007247A9 /* Assets.xcassets */; };
|
||||
C026375E1F1C25E8007247A9 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C026375C1F1C25E8007247A9 /* LaunchScreen.storyboard */; };
|
||||
C02637661F1C2690007247A9 /* TVMRuntime.mm in Sources */ = {isa = PBXBuildFile; fileRef = C02637651F1C2690007247A9 /* TVMRuntime.mm */; };
|
||||
C02637691F1C26AF007247A9 /* ViewController.mm in Sources */ = {isa = PBXBuildFile; fileRef = C02637681F1C26AF007247A9 /* ViewController.mm */; };
|
||||
D7685AD324390EAE00D1469C /* CoreML.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D7685AD224390EAD00D1469C /* CoreML.framework */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
01A9B7B9265BD307000D092F /* Embed Libraries */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
dstPath = "";
|
||||
dstSubfolderSpec = 10;
|
||||
files = (
|
||||
01A9B7B8265BD307000D092F /* libtvm_runtime.dylib in Embed Libraries */,
|
||||
);
|
||||
name = "Embed Libraries";
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
016B19C02657B390002E1719 /* RPCServer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RPCServer.h; sourceTree = "<group>"; };
|
||||
016B19C12657B390002E1719 /* RPCServer.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = RPCServer.mm; sourceTree = "<group>"; };
|
||||
01A1DB402652CBA700655BBC /* RPCArgs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RPCArgs.h; sourceTree = "<group>"; };
|
||||
01A1DB412652CBA700655BBC /* RPCArgs.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = RPCArgs.mm; sourceTree = "<group>"; };
|
||||
01A9B7B2265BD1FD000D092F /* libtvm_runtime.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libtvm_runtime.dylib; path = "${TVM_BUILD_DIR}/libtvm_runtime.dylib"; sourceTree = "<group>"; };
|
||||
C026374B1F1C25E8007247A9 /* tvmrpc.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = tvmrpc.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
C026374F1F1C25E8007247A9 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
|
||||
C02637511F1C25E8007247A9 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
|
||||
C02637521F1C25E8007247A9 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
|
||||
C02637541F1C25E8007247A9 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = "<group>"; };
|
||||
C02637581F1C25E8007247A9 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
|
||||
C026375A1F1C25E8007247A9 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||
C026375D1F1C25E8007247A9 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||
C026375F1F1C25E8007247A9 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
C02637651F1C2690007247A9 /* TVMRuntime.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = TVMRuntime.mm; sourceTree = "<group>"; };
|
||||
C02637681F1C26AF007247A9 /* ViewController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ViewController.mm; sourceTree = "<group>"; };
|
||||
D7685AD224390EAD00D1469C /* CoreML.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreML.framework; path = System/Library/Frameworks/CoreML.framework; sourceTree = SDKROOT; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
C02637481F1C25E8007247A9 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
01A9B7B3265BD1FD000D092F /* libtvm_runtime.dylib in Frameworks */,
|
||||
D7685AD324390EAE00D1469C /* CoreML.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
C02637421F1C25E8007247A9 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
C026374D1F1C25E8007247A9 /* tvmrpc */,
|
||||
C026374C1F1C25E8007247A9 /* Products */,
|
||||
D7685AD124390EAD00D1469C /* Frameworks */,
|
||||
);
|
||||
indentWidth = 2;
|
||||
sourceTree = "<group>";
|
||||
tabWidth = 2;
|
||||
};
|
||||
C026374C1F1C25E8007247A9 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
C026374B1F1C25E8007247A9 /* tvmrpc.app */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
C026374D1F1C25E8007247A9 /* tvmrpc */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
016B19C02657B390002E1719 /* RPCServer.h */,
|
||||
016B19C12657B390002E1719 /* RPCServer.mm */,
|
||||
01A1DB402652CBA700655BBC /* RPCArgs.h */,
|
||||
01A1DB412652CBA700655BBC /* RPCArgs.mm */,
|
||||
C02637651F1C2690007247A9 /* TVMRuntime.mm */,
|
||||
C02637511F1C25E8007247A9 /* AppDelegate.h */,
|
||||
C02637521F1C25E8007247A9 /* AppDelegate.m */,
|
||||
C02637541F1C25E8007247A9 /* ViewController.h */,
|
||||
C02637681F1C26AF007247A9 /* ViewController.mm */,
|
||||
C02637571F1C25E8007247A9 /* Main.storyboard */,
|
||||
C026375A1F1C25E8007247A9 /* Assets.xcassets */,
|
||||
C026375C1F1C25E8007247A9 /* LaunchScreen.storyboard */,
|
||||
C026375F1F1C25E8007247A9 /* Info.plist */,
|
||||
C026374E1F1C25E8007247A9 /* Supporting Files */,
|
||||
);
|
||||
path = tvmrpc;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
C026374E1F1C25E8007247A9 /* Supporting Files */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
C026374F1F1C25E8007247A9 /* main.m */,
|
||||
);
|
||||
name = "Supporting Files";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
D7685AD124390EAD00D1469C /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
01A9B7B2265BD1FD000D092F /* libtvm_runtime.dylib */,
|
||||
D7685AD224390EAD00D1469C /* CoreML.framework */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
C026374A1F1C25E8007247A9 /* tvmrpc */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = C02637621F1C25E8007247A9 /* Build configuration list for PBXNativeTarget "tvmrpc" */;
|
||||
buildPhases = (
|
||||
C02637471F1C25E8007247A9 /* Sources */,
|
||||
C02637481F1C25E8007247A9 /* Frameworks */,
|
||||
C02637491F1C25E8007247A9 /* Resources */,
|
||||
01A9B7B9265BD307000D092F /* Embed Libraries */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = tvmrpc;
|
||||
productName = tvmrpc;
|
||||
productReference = C026374B1F1C25E8007247A9 /* tvmrpc.app */;
|
||||
productType = "com.apple.product-type.application";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
C02637431F1C25E8007247A9 /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastUpgradeCheck = 0830;
|
||||
ORGANIZATIONNAME = dmlc;
|
||||
TargetAttributes = {
|
||||
C026374A1F1C25E8007247A9 = {
|
||||
CreatedOnToolsVersion = 8.3.3;
|
||||
DevelopmentTeam = 3FR42MXLK9;
|
||||
ProvisioningStyle = Automatic;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = C02637461F1C25E8007247A9 /* Build configuration list for PBXProject "tvmrpc" */;
|
||||
compatibilityVersion = "Xcode 3.2";
|
||||
developmentRegion = English;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
English,
|
||||
en,
|
||||
Base,
|
||||
);
|
||||
mainGroup = C02637421F1C25E8007247A9;
|
||||
productRefGroup = C026374C1F1C25E8007247A9 /* Products */;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
C026374A1F1C25E8007247A9 /* tvmrpc */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXResourcesBuildPhase section */
|
||||
C02637491F1C25E8007247A9 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
C026375E1F1C25E8007247A9 /* LaunchScreen.storyboard in Resources */,
|
||||
C026375B1F1C25E8007247A9 /* Assets.xcassets in Resources */,
|
||||
C02637591F1C25E8007247A9 /* Main.storyboard in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
C02637471F1C25E8007247A9 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
C02637691F1C26AF007247A9 /* ViewController.mm in Sources */,
|
||||
01A1DB432652CBA700655BBC /* RPCArgs.mm in Sources */,
|
||||
016B19C22657B390002E1719 /* RPCServer.mm in Sources */,
|
||||
C02637531F1C25E8007247A9 /* AppDelegate.m in Sources */,
|
||||
C02637661F1C2690007247A9 /* TVMRuntime.mm in Sources */,
|
||||
C02637501F1C25E8007247A9 /* main.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXVariantGroup section */
|
||||
C02637571F1C25E8007247A9 /* Main.storyboard */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
C02637581F1C25E8007247A9 /* Base */,
|
||||
);
|
||||
name = Main.storyboard;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
C026375C1F1C25E8007247A9 /* LaunchScreen.storyboard */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
C026375D1F1C25E8007247A9 /* Base */,
|
||||
);
|
||||
name = LaunchScreen.storyboard;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXVariantGroup section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
C02637601F1C25E8007247A9 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
ENABLE_BITCODE = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
"$(inherited)",
|
||||
"TVM_LOG_CUSTOMIZE=1",
|
||||
);
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 10.3;
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
C02637611F1C25E8007247A9 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_BITCODE = NO;
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"TVM_LOG_CUSTOMIZE=1",
|
||||
);
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 10.3;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = iphoneos;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VALIDATE_PRODUCT = YES;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
C02637631F1C25E8007247A9 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = NO;
|
||||
DEVELOPMENT_TEAM = 3FR42MXLK9;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"$(inherited)",
|
||||
"USE_CUSTOM_DSO_LOADER=${USE_CUSTOM_DSO_LOADER}",
|
||||
);
|
||||
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
|
||||
HEADER_SEARCH_PATHS = (
|
||||
../../include,
|
||||
../../3rdparty/dlpack/include,
|
||||
"${TVM_BUILD_DIR}/apps/ios_rpc/custom_dso_loader/include",
|
||||
);
|
||||
INFOPLIST_FILE = tvmrpc/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
LIBRARY_SEARCH_PATHS = (
|
||||
"${TVM_BUILD_DIR}/apps/ios_rpc/custom_dso_loader/lib",
|
||||
"${TVM_BUILD_DIR}",
|
||||
);
|
||||
OTHER_LDFLAGS = "${_DSO_LOADER_NAME_${USE_CUSTOM_DSO_LOADER}}";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.apache.tvmiosrpc;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
TVM_BUILD_DIR = "path-to-tvm-ios-build-folder";
|
||||
USE_CUSTOM_DSO_LOADER = 1;
|
||||
WARNING_CFLAGS = "-Wno-shorten-64-to-32";
|
||||
_DSO_LOADER_NAME_0 = "";
|
||||
_DSO_LOADER_NAME_1 = "-lmacho_dyld";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
C02637641F1C25E8007247A9 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = NO;
|
||||
DEVELOPMENT_TEAM = 3FR42MXLK9;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"$(inherited)",
|
||||
"USE_CUSTOM_DSO_LOADER=${USE_CUSTOM_DSO_LOADER}",
|
||||
);
|
||||
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
|
||||
HEADER_SEARCH_PATHS = (
|
||||
../../include,
|
||||
../../3rdparty/dlpack/include,
|
||||
"${TVM_BUILD_DIR}/apps/ios_rpc/custom_dso_loader/include",
|
||||
);
|
||||
INFOPLIST_FILE = tvmrpc/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
LIBRARY_SEARCH_PATHS = (
|
||||
"${TVM_BUILD_DIR}/apps/ios_rpc/custom_dso_loader/lib",
|
||||
"${TVM_BUILD_DIR}",
|
||||
);
|
||||
OTHER_LDFLAGS = "${_DSO_LOADER_NAME_${USE_CUSTOM_DSO_LOADER}}";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.apache.tvmiosrpc;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
TVM_BUILD_DIR = "path-to-tvm-ios-build-folder";
|
||||
USE_CUSTOM_DSO_LOADER = 1;
|
||||
WARNING_CFLAGS = "-Wno-shorten-64-to-32";
|
||||
_DSO_LOADER_NAME_0 = "";
|
||||
_DSO_LOADER_NAME_1 = "-lmacho_dyld";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
C02637461F1C25E8007247A9 /* Build configuration list for PBXProject "tvmrpc" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
C02637601F1C25E8007247A9 /* Debug */,
|
||||
C02637611F1C25E8007247A9 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
C02637621F1C25E8007247A9 /* Build configuration list for PBXNativeTarget "tvmrpc" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
C02637631F1C25E8007247A9 /* Debug */,
|
||||
C02637641F1C25E8007247A9 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = C02637431F1C25E8007247A9 /* Project object */;
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--- Licensed to the Apache Software Foundation (ASF) under one -->
|
||||
<!--- or more contributor license agreements. See the NOTICE file -->
|
||||
<!--- distributed with this work for additional information -->
|
||||
<!--- regarding copyright ownership. The ASF licenses this file -->
|
||||
<!--- to you under the Apache License, Version 2.0 (the -->
|
||||
<!--- "License"); you may not use this file except in compliance -->
|
||||
<!--- with the License. You may obtain a copy of the License at -->
|
||||
|
||||
<!--- http://www.apache.org/licenses/LICENSE-2.0 -->
|
||||
|
||||
<!--- Unless required by applicable law or agreed to in writing, -->
|
||||
<!--- software distributed under the License is distributed on an -->
|
||||
<!--- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -->
|
||||
<!--- KIND, either express or implied. See the License for the -->
|
||||
<!--- specific language governing permissions and limitations -->
|
||||
<!--- under the License. -->
|
||||
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "self:tvmrpc.xcodeproj">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
@@ -0,0 +1,95 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--- Licensed to the Apache Software Foundation (ASF) under one -->
|
||||
<!--- or more contributor license agreements. See the NOTICE file -->
|
||||
<!--- distributed with this work for additional information -->
|
||||
<!--- regarding copyright ownership. The ASF licenses this file -->
|
||||
<!--- to you under the Apache License, Version 2.0 (the -->
|
||||
<!--- "License"); you may not use this file except in compliance -->
|
||||
<!--- with the License. You may obtain a copy of the License at -->
|
||||
|
||||
<!--- http://www.apache.org/licenses/LICENSE-2.0 -->
|
||||
|
||||
<!--- Unless required by applicable law or agreed to in writing, -->
|
||||
<!--- software distributed under the License is distributed on an -->
|
||||
<!--- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -->
|
||||
<!--- KIND, either express or implied. See the License for the -->
|
||||
<!--- specific language governing permissions and limitations -->
|
||||
<!--- under the License. -->
|
||||
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1250"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "C026374A1F1C25E8007247A9"
|
||||
BuildableName = "tvmrpc.app"
|
||||
BlueprintName = "tvmrpc"
|
||||
ReferencedContainer = "container:tvmrpc.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
</Testables>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "C026374A1F1C25E8007247A9"
|
||||
BuildableName = "tvmrpc.app"
|
||||
BlueprintName = "tvmrpc"
|
||||
ReferencedContainer = "container:tvmrpc.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "C026374A1F1C25E8007247A9"
|
||||
BuildableName = "tvmrpc.app"
|
||||
BlueprintName = "tvmrpc"
|
||||
ReferencedContainer = "container:tvmrpc.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \file AppDelegate.h
|
||||
*/
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface AppDelegate : UIResponder <UIApplicationDelegate>
|
||||
|
||||
@property(strong, nonatomic) UIWindow* window;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \file AppDelegate.mm
|
||||
*/
|
||||
|
||||
#import "AppDelegate.h"
|
||||
|
||||
@interface AppDelegate ()
|
||||
|
||||
@end
|
||||
|
||||
@implementation AppDelegate
|
||||
|
||||
- (BOOL)application:(UIApplication*)application
|
||||
didFinishLaunchingWithOptions:(NSDictionary*)launchOptions {
|
||||
// Override point for customization after application launch.
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)applicationWillResignActive:(UIApplication*)application {
|
||||
// Sent when the application is about to move from active to inactive state. This can occur for
|
||||
// certain types of temporary interruptions (such as an incoming phone call or SMS message) or
|
||||
// when the user quits the application and it begins the transition to the background state. Use
|
||||
// this method to pause ongoing tasks, disable timers, and invalidate graphics rendering
|
||||
// callbacks. Games should use this method to pause the game.
|
||||
}
|
||||
|
||||
- (void)applicationDidEnterBackground:(UIApplication*)application {
|
||||
// Use this method to release shared resources, save user data, invalidate timers, and store
|
||||
// enough application state information to restore your application to its current state in case
|
||||
// it is terminated later. If your application supports background execution, this method is
|
||||
// called instead of applicationWillTerminate: when the user quits.
|
||||
}
|
||||
|
||||
- (void)applicationWillEnterForeground:(UIApplication*)application {
|
||||
// Called as part of the transition from the background to the active state; here you can undo
|
||||
// many of the changes made on entering the background.
|
||||
}
|
||||
|
||||
- (void)applicationDidBecomeActive:(UIApplication*)application {
|
||||
// Restart any tasks that were paused (or not yet started) while the application was inactive. If
|
||||
// the application was previously in the background, optionally refresh the user interface.
|
||||
}
|
||||
|
||||
- (void)applicationWillTerminate:(UIApplication*)application {
|
||||
// Called when the application is about to terminate. Save data if appropriate. See also
|
||||
// applicationDidEnterBackground:.
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,47 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
|
||||
<!--
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
-->
|
||||
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="11134" systemVersion="15F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11106"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
<!--View Controller-->
|
||||
<scene sceneID="EHf-IW-A2E">
|
||||
<objects>
|
||||
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
|
||||
<layoutGuides>
|
||||
<viewControllerLayoutGuide type="top" id="Llm-lL-Icb"/>
|
||||
<viewControllerLayoutGuide type="bottom" id="xb3-aO-Qok"/>
|
||||
</layoutGuides>
|
||||
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</view>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="53" y="375"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
</document>
|
||||
@@ -0,0 +1,127 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--- Licensed to the Apache Software Foundation (ASF) under one -->
|
||||
<!--- or more contributor license agreements. See the NOTICE file -->
|
||||
<!--- distributed with this work for additional information -->
|
||||
<!--- regarding copyright ownership. The ASF licenses this file -->
|
||||
<!--- to you under the Apache License, Version 2.0 (the -->
|
||||
<!--- "License"); you may not use this file except in compliance -->
|
||||
<!--- with the License. You may obtain a copy of the License at -->
|
||||
|
||||
<!--- http://www.apache.org/licenses/LICENSE-2.0 -->
|
||||
|
||||
<!--- Unless required by applicable law or agreed to in writing, -->
|
||||
<!--- software distributed under the License is distributed on an -->
|
||||
<!--- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -->
|
||||
<!--- KIND, either express or implied. See the License for the -->
|
||||
<!--- specific language governing permissions and limitations -->
|
||||
<!--- under the License. -->
|
||||
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="17701" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
|
||||
<device id="retina5_5" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17703"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
<!--View Controller-->
|
||||
<scene sceneID="tne-QT-ifu">
|
||||
<objects>
|
||||
<viewController id="BYZ-38-t0r" customClass="ViewController" sceneMemberID="viewController">
|
||||
<layoutGuides>
|
||||
<viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
|
||||
<viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
|
||||
</layoutGuides>
|
||||
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="736"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="left" contentVerticalAlignment="center" text="9090" borderStyle="roundedRect" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="eLf-oe-8c9">
|
||||
<rect key="frame" x="110" y="186" width="234" height="30"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="14"/>
|
||||
<textInputTraits key="textInputTraits"/>
|
||||
</textField>
|
||||
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="left" contentVerticalAlignment="center" text="iphone" borderStyle="roundedRect" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="o4Q-bP-8Cn">
|
||||
<rect key="frame" x="110" y="224" width="234" height="30"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="14"/>
|
||||
<textInputTraits key="textInputTraits"/>
|
||||
</textField>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="Address" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Vkh-HN-g3u">
|
||||
<rect key="frame" x="39" y="148" width="63" height="27"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="Port" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="vtu-2M-JLP">
|
||||
<rect key="frame" x="61" y="186" width="41" height="30"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="Key" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="5MW-dM-69p">
|
||||
<rect key="frame" x="61" y="224" width="41" height="30"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="7yQ-tQ-Qqc">
|
||||
<rect key="frame" x="110" y="148" width="234" height="30"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="14"/>
|
||||
<textInputTraits key="textInputTraits"/>
|
||||
</textField>
|
||||
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" fixedFrame="YES" editable="NO" textAlignment="natural" translatesAutoresizingMaskIntoConstraints="NO" id="8jt-IO-eTb">
|
||||
<rect key="frame" x="69" y="374" width="254" height="207"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="14"/>
|
||||
<textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
|
||||
</textView>
|
||||
<segmentedControl opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="0" translatesAutoresizingMaskIntoConstraints="NO" id="ocx-rT-xCk">
|
||||
<rect key="frame" x="110" y="262" width="234" height="32"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<segments>
|
||||
<segment title="Tracker"/>
|
||||
<segment title="Proxy"/>
|
||||
<segment title="RPC"/>
|
||||
</segments>
|
||||
</segmentedControl>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="Disconnected" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="9Zy-zO-r1A">
|
||||
<rect key="frame" x="143" y="99" width="106" height="20.5"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="m1Y-7m-LeH">
|
||||
<rect key="frame" x="110" y="306" width="234" height="60"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<state key="normal" title="Connect"/>
|
||||
<connections>
|
||||
<action selector="connect:" destination="BYZ-38-t0r" eventType="touchUpInside" id="1cx-nV-onb"/>
|
||||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</view>
|
||||
<connections>
|
||||
<outlet property="ConnectButton" destination="m1Y-7m-LeH" id="Pc5-Cl-uxz"/>
|
||||
<outlet property="ModeSelector" destination="ocx-rT-xCk" id="5r7-XQ-tMk"/>
|
||||
<outlet property="infoText" destination="8jt-IO-eTb" id="TmG-H2-eJY"/>
|
||||
<outlet property="proxyKey" destination="o4Q-bP-8Cn" id="XFh-Qz-86e"/>
|
||||
<outlet property="proxyPort" destination="eLf-oe-8c9" id="f1g-tu-Q5U"/>
|
||||
<outlet property="proxyURL" destination="7yQ-tQ-Qqc" id="KBr-zC-3sD"/>
|
||||
<outlet property="statusLabel" destination="9Zy-zO-r1A" id="gHN-jG-4ii"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="24.800000000000001" y="36.431784107946029"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
</document>
|
||||
@@ -0,0 +1,62 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--- Licensed to the Apache Software Foundation (ASF) under one -->
|
||||
<!--- or more contributor license agreements. See the NOTICE file -->
|
||||
<!--- distributed with this work for additional information -->
|
||||
<!--- regarding copyright ownership. The ASF licenses this file -->
|
||||
<!--- to you under the Apache License, Version 2.0 (the -->
|
||||
<!--- "License"); you may not use this file except in compliance -->
|
||||
<!--- with the License. You may obtain a copy of the License at -->
|
||||
|
||||
<!--- http://www.apache.org/licenses/LICENSE-2.0 -->
|
||||
|
||||
<!--- Unless required by applicable law or agreed to in writing, -->
|
||||
<!--- software distributed under the License is distributed on an -->
|
||||
<!--- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -->
|
||||
<!--- KIND, either express or implied. See the License for the -->
|
||||
<!--- specific language governing permissions and limitations -->
|
||||
<!--- under the License. -->
|
||||
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
<string>LaunchScreen</string>
|
||||
<key>UIMainStoryboardFile</key>
|
||||
<string>Main</string>
|
||||
<key>UIRequiredDeviceCapabilities</key>
|
||||
<array>
|
||||
<string>armv7</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations~ipad</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifndef TVM_APPS_IOS_RPC_ARGS_H_
|
||||
#define TVM_APPS_IOS_RPC_ARGS_H_
|
||||
|
||||
#import "RPCServer.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*!
|
||||
* \brief Struct representing arguments of iOS RPC app
|
||||
*/
|
||||
typedef struct RPCArgs_t {
|
||||
/// Tracker or Proxy address (actually ip)
|
||||
const char* host_url;
|
||||
|
||||
/// Tracker or Proxy port
|
||||
int host_port;
|
||||
|
||||
/// device key to report
|
||||
const char* key;
|
||||
|
||||
/// custom address to report into Tracker. Ignored for other server modes.
|
||||
const char* custom_addr;
|
||||
|
||||
/// Verbose mode. Will print status messages to std out.
|
||||
/// 0 - no prints , 1 - print state to output
|
||||
bool verbose;
|
||||
|
||||
/// Immediate server launch. No UI interaction.
|
||||
/// 0 - UI interaction, 1 - automatically connect on launch
|
||||
bool immediate_connect;
|
||||
|
||||
/// Server mode
|
||||
RPCServerMode server_mode;
|
||||
} RPCArgs;
|
||||
|
||||
/*!
|
||||
* \brief Get current global RPC args
|
||||
*/
|
||||
RPCArgs get_current_rpc_args(void);
|
||||
|
||||
/*!
|
||||
* \brief Set current global RPC args and update values in app cache
|
||||
*/
|
||||
void set_current_rpc_args(RPCArgs args);
|
||||
|
||||
/*!
|
||||
* \brief Pars command line args and update current global RPC args
|
||||
* Also updates values in app cache
|
||||
*/
|
||||
void update_rpc_args(int argc, char* argv[]);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // TVM_APPS_IOS_RPC_ARGS_H_
|
||||
@@ -0,0 +1,197 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#import "RPCArgs.h"
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import "../../../src/support/socket.h"
|
||||
#import "../../../src/support/utils.h"
|
||||
|
||||
#import <string>
|
||||
|
||||
using std::string;
|
||||
|
||||
const char* kUsage =
|
||||
"\n"
|
||||
"iOS tvmrpc application supported flags:\n"
|
||||
"--host_url The tracker/proxy address, Default=0.0.0.0\n"
|
||||
"--host_port The tracker/proxy port, Default=9190\n"
|
||||
"--key The key used to identify the device type in tracker. Default=\"\"\n"
|
||||
"--custom_addr Custom IP Address to Report to RPC Tracker. Default=\"\"\n"
|
||||
"--immediate_connect No UI interconnection, connect to tracker immediately. Default=False\n"
|
||||
"--verbose Allow to print status info to std out. Default=False\n"
|
||||
"--server_mode Server mode. Can be \"standalone\", \"proxy\" or \"tracker\". "
|
||||
"Default=standalone \n"
|
||||
"\n";
|
||||
|
||||
struct RPCArgs_cpp {
|
||||
string host_url = "0.0.0.0";
|
||||
int host_port = 9190;
|
||||
|
||||
string key;
|
||||
string custom_addr = "null";
|
||||
|
||||
bool immediate_connect = false;
|
||||
bool verbose = false;
|
||||
RPCServerMode server_mode = RPCServerMode_Tracker;
|
||||
|
||||
operator RPCArgs() const {
|
||||
return RPCArgs{.host_url = host_url.c_str(),
|
||||
.host_port = host_port,
|
||||
.key = key.c_str(),
|
||||
.custom_addr = custom_addr.c_str(),
|
||||
.verbose = verbose,
|
||||
.immediate_connect = immediate_connect,
|
||||
.server_mode = server_mode};
|
||||
};
|
||||
|
||||
RPCArgs_cpp& operator=(const RPCArgs& args) {
|
||||
host_url = args.host_url;
|
||||
host_port = args.host_port;
|
||||
key = args.key;
|
||||
custom_addr = args.custom_addr;
|
||||
verbose = args.verbose;
|
||||
immediate_connect = args.immediate_connect;
|
||||
server_mode = args.server_mode;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
struct RPCArgs_cpp g_rpc_args;
|
||||
|
||||
static void restore_from_cache() {
|
||||
NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
|
||||
|
||||
auto get_string_from_cache = [defaults](const char* key) {
|
||||
NSString* ns_key = [NSString stringWithUTF8String:key];
|
||||
NSString* ns_val = [defaults stringForKey:ns_key];
|
||||
return std::string(ns_val != nil ? [ns_val UTF8String] : "");
|
||||
};
|
||||
|
||||
auto get_int_from_cache = [defaults](const char* key) {
|
||||
NSString* ns_key = [NSString stringWithUTF8String:key];
|
||||
return static_cast<int>([defaults integerForKey:ns_key]);
|
||||
};
|
||||
|
||||
g_rpc_args.host_url = get_string_from_cache("RPCArgs_url");
|
||||
g_rpc_args.host_port = get_int_from_cache("RPCArgs_port");
|
||||
g_rpc_args.key = get_string_from_cache("RPCArgs_key");
|
||||
}
|
||||
|
||||
static void update_in_cache() {
|
||||
NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
|
||||
|
||||
[defaults setObject:[NSString stringWithUTF8String:g_rpc_args.host_url.c_str()]
|
||||
forKey:@"RPCArgs_url"];
|
||||
[defaults setInteger:g_rpc_args.host_port forKey:@"RPCArgs_port"];
|
||||
[defaults setObject:[NSString stringWithUTF8String:g_rpc_args.key.c_str()] forKey:@"RPCArgs_key"];
|
||||
}
|
||||
|
||||
string GetCmdOption(int argc, char* argv[], string option, bool key = false) {
|
||||
string cmd;
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
string arg = argv[i];
|
||||
if (arg.find(option) == 0) {
|
||||
if (key) {
|
||||
cmd = argv[i];
|
||||
return cmd;
|
||||
}
|
||||
// We assume "=" is the end of option.
|
||||
TVM_FFI_ICHECK_EQ(*option.rbegin(), '=');
|
||||
cmd = arg.substr(arg.find('=') + 1);
|
||||
return cmd;
|
||||
}
|
||||
}
|
||||
return cmd;
|
||||
}
|
||||
|
||||
void update_rpc_args(int argc, char* argv[]) {
|
||||
restore_from_cache();
|
||||
RPCArgs_cpp& args = g_rpc_args;
|
||||
|
||||
using tvm::support::IsNumber;
|
||||
using tvm::support::ValidateIP;
|
||||
constexpr int MAX_PORT_NUM = 65535;
|
||||
|
||||
const string immediate_connect = GetCmdOption(argc, argv, "--immediate_connect", true);
|
||||
args.immediate_connect = !immediate_connect.empty();
|
||||
|
||||
const string verbose = GetCmdOption(argc, argv, "--verbose", true);
|
||||
args.verbose = !verbose.empty();
|
||||
|
||||
const string server_mode = GetCmdOption(argc, argv, "--server_mode=", false);
|
||||
if (!server_mode.empty()) {
|
||||
if (server_mode == "tracker") {
|
||||
args.server_mode = RPCServerMode_Tracker;
|
||||
} else if (server_mode == "proxy") {
|
||||
args.server_mode = RPCServerMode_Proxy;
|
||||
} else if (server_mode == "standalone") {
|
||||
args.server_mode = RPCServerMode_Standalone;
|
||||
} else {
|
||||
LOG(WARNING) << "Wrong server_mode value.";
|
||||
LOG(INFO) << kUsage;
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
const string host_url = GetCmdOption(argc, argv, "--host_url=");
|
||||
if (!host_url.empty()) {
|
||||
if (!ValidateIP(host_url)) {
|
||||
LOG(WARNING) << "Wrong tracker address format.";
|
||||
LOG(INFO) << kUsage;
|
||||
exit(1);
|
||||
}
|
||||
args.host_url = host_url;
|
||||
}
|
||||
|
||||
const string host_port = GetCmdOption(argc, argv, "--host_port=");
|
||||
if (!host_port.empty()) {
|
||||
if (!IsNumber(host_port) || stoi(host_port) > MAX_PORT_NUM) {
|
||||
LOG(WARNING) << "Wrong trackerport number.";
|
||||
LOG(INFO) << kUsage;
|
||||
exit(1);
|
||||
}
|
||||
args.host_port = stoi(host_port);
|
||||
}
|
||||
|
||||
const string key = GetCmdOption(argc, argv, "--key=");
|
||||
if (!key.empty()) {
|
||||
args.key = key;
|
||||
}
|
||||
|
||||
const string custom_addr = GetCmdOption(argc, argv, "--custom_addr=");
|
||||
if (!custom_addr.empty()) {
|
||||
if (!ValidateIP(custom_addr)) {
|
||||
LOG(WARNING) << "Wrong custom address format.";
|
||||
LOG(INFO) << kUsage;
|
||||
exit(1);
|
||||
}
|
||||
args.custom_addr = '"' + custom_addr + '"';
|
||||
}
|
||||
|
||||
update_in_cache();
|
||||
}
|
||||
|
||||
RPCArgs get_current_rpc_args(void) { return g_rpc_args; }
|
||||
|
||||
void set_current_rpc_args(RPCArgs args) {
|
||||
g_rpc_args = args;
|
||||
update_in_cache();
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \file Provide interfaces to launch and control RPC Service routine
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
/*!
|
||||
* \brief Enum with possible status of RPC server
|
||||
* Used to report state to listener
|
||||
*/
|
||||
typedef enum {
|
||||
RPCServerStatus_Launched, // Worker thread is launched
|
||||
RPCServerStatus_Stopped, // Worker thread stopped
|
||||
RPCServerStatus_Connected, // Connected to Proxy/Tracker
|
||||
RPCServerStatus_Disconnected, // Disconnected from Proxy/Tracker
|
||||
RPCServerStatus_RPCSessionStarted, // RPC session is started
|
||||
RPCServerStatus_RPCSessionFinished // RPC session is finished
|
||||
} RPCServerStatus;
|
||||
|
||||
/*!
|
||||
* \brief Enum with modes of servicing supported by RPCServer
|
||||
*/
|
||||
typedef enum {
|
||||
/// Tracker mode. Same as Standalone Server plus register it into Tracker.
|
||||
RPCServerMode_Tracker,
|
||||
/// Proxy mode. Connect to proxy server and wait response.
|
||||
RPCServerMode_Proxy,
|
||||
/// Standalone RPC server mode. Open port with RPC server and wait incoming connection.
|
||||
RPCServerMode_Standalone
|
||||
} RPCServerMode;
|
||||
|
||||
/*!
|
||||
* \brief Listener for events happened with RPCServer
|
||||
*/
|
||||
@protocol RPCServerEventListener <NSObject>
|
||||
/// Callback to notifying about new status
|
||||
- (void)onError:(NSString*)msg;
|
||||
/// Callback to notifying about error
|
||||
- (void)onStatusChanged:(RPCServerStatus)status;
|
||||
@end
|
||||
|
||||
/*!
|
||||
* \brief RPC Server instance
|
||||
* Contains internal worker thread plus
|
||||
*/
|
||||
@interface RPCServer : NSObject <NSStreamDelegate>
|
||||
|
||||
/// Event listener delegate to set
|
||||
@property(retain) id<RPCServerEventListener> delegate;
|
||||
/// Device key to report during RPC session
|
||||
@property(retain) NSString* key;
|
||||
/// Host address of Proxy/Tracker server (generally IPv4). Ignored for Standalone mode.
|
||||
@property(retain) NSString* host;
|
||||
/// Port of Proxy/Tracker server. Ignored for Standalone mode.
|
||||
@property int port;
|
||||
/// Custom address to report into tracker server (optional). Ignored for Standalone/Proxy modes
|
||||
@property(retain) NSString* custom_addr;
|
||||
/// Trigger to enable printing of server state info
|
||||
@property BOOL verbose;
|
||||
/// RPC port opened on the device. Ignored for Proxy/Tracker modes
|
||||
@property int actual_port;
|
||||
/// IP address of the device. Ignored for Proxy/Tracker modes
|
||||
@property(retain) NSString* device_addr;
|
||||
|
||||
/*!
|
||||
* \brief Create server with specified servicing mode
|
||||
* \param mode Mode of server
|
||||
*/
|
||||
+ (instancetype)serverWithMode:(RPCServerMode)mode;
|
||||
|
||||
/*!
|
||||
* \brief Start RPC server with options. Non blocking method
|
||||
*/
|
||||
- (void)start;
|
||||
|
||||
/*!
|
||||
* \brief Stop RPC server. Non blocking method
|
||||
*/
|
||||
- (void)stop;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,814 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \file ViewController.mm
|
||||
*/
|
||||
|
||||
#import "RPCServer.h"
|
||||
|
||||
#include <tvm/ffi/function.h>
|
||||
|
||||
#include <random>
|
||||
#include <string>
|
||||
|
||||
// To get device WiFi IP
|
||||
#include <arpa/inet.h>
|
||||
#include <ifaddrs.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
// TVM internal header to access Magic keys like kRPCMagic and others
|
||||
#include "../../../src/runtime/rpc/rpc_endpoint.h"
|
||||
|
||||
namespace tvm {
|
||||
namespace runtime {
|
||||
|
||||
/*!
|
||||
* \brief Message handling function for event driven server.
|
||||
*
|
||||
* \param in_bytes The incoming bytes.
|
||||
* \param event_flag 1: read_available, 2: write_avaiable.
|
||||
* \return State flag.
|
||||
* 1: continue running, no need to write,
|
||||
* 2: need to write
|
||||
* 0: shutdown
|
||||
*/
|
||||
using FEventHandler = ffi::Function;
|
||||
|
||||
/*!
|
||||
* \brief Create a server event handler.
|
||||
*
|
||||
* \param outputStream The output stream used to send outputs.
|
||||
* \param name The name of the server.
|
||||
* \param remote_key The remote key
|
||||
* \return The event handler.
|
||||
*/
|
||||
FEventHandler CreateServerEventHandler(NSOutputStream* outputStream, std::string name,
|
||||
std::string remote_key) {
|
||||
auto event_handler_factory = tvm::ffi::Function::GetGlobal("rpc.CreateEventDrivenServer");
|
||||
TVM_FFI_ICHECK(event_handler_factory.has_value())
|
||||
<< "You are using tvm_runtime module built without RPC support. "
|
||||
<< "Please rebuild it with USE_RPC flag.";
|
||||
|
||||
ffi::Function writer_func([outputStream](ffi::PackedArgs args, ffi::Any* rv) {
|
||||
TVMByteArray* data = args[0].ptr<TVMByteArray>();
|
||||
int64_t nbytes = [outputStream write:reinterpret_cast<const uint8_t*>(data->data)
|
||||
maxLength:data->size];
|
||||
if (nbytes < 0) {
|
||||
NSLog(@"%@", [outputStream streamError].localizedDescription);
|
||||
throw tvm::Error("Stream error");
|
||||
}
|
||||
*rv = nbytes;
|
||||
});
|
||||
|
||||
return (*event_handler_factory)(writer_func, name, remote_key);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Helper function to query real IP of device in WiFi network
|
||||
* \return string with IPv4 in format "192.168.0.1" or "unknown" if cannot detect
|
||||
*/
|
||||
static std::string getWiFiAddress() {
|
||||
std::string address = "unknown";
|
||||
ifaddrs* interfaces = nullptr;
|
||||
|
||||
int success = getifaddrs(&interfaces);
|
||||
if (success == 0) {
|
||||
ifaddrs* temp_addr = interfaces;
|
||||
while (temp_addr != NULL) {
|
||||
if (temp_addr->ifa_addr->sa_family == AF_INET) {
|
||||
// Check if interface is en0 which is the wifi connection on the iPhone
|
||||
if (std::string(temp_addr->ifa_name) == "en0") {
|
||||
address = inet_ntoa(((sockaddr_in*)temp_addr->ifa_addr)->sin_addr);
|
||||
}
|
||||
}
|
||||
temp_addr = temp_addr->ifa_next;
|
||||
}
|
||||
}
|
||||
|
||||
freeifaddrs(interfaces);
|
||||
return address;
|
||||
}
|
||||
|
||||
} // namespace runtime
|
||||
} // namespace tvm
|
||||
|
||||
// Base class for any type of RPC servicing
|
||||
@interface RPCServerBase : RPCServer
|
||||
|
||||
/*!
|
||||
* Methods should be implemented in inherited classes
|
||||
*/
|
||||
- (bool)onReadHandler; // return true - continue feeding, false - stop, try to drain output buffer
|
||||
- (bool)onWriteHandler; // return true - continue draining, false - no data to write
|
||||
- (void)onEndEncountered; // called on disconnect or session decided that it's shutdown time
|
||||
- (void)open; // Initiate listening objects like i/o streams and other resources
|
||||
- (void)close; // Deinitialize resources opend in "open" method
|
||||
@end
|
||||
|
||||
@implementation RPCServerBase {
|
||||
// Worker thread
|
||||
NSThread* worker_thread_;
|
||||
// Trigger to continue RunLoop processing inside worker_thread_
|
||||
BOOL shouldKeepRunning;
|
||||
// Input socket stream
|
||||
@protected
|
||||
NSInputStream* inputStream_;
|
||||
// Output socket stream
|
||||
NSOutputStream* outputStream_;
|
||||
// Temporal buffer with data to send
|
||||
std::string sendBuffer_;
|
||||
// Temporal receive buffer
|
||||
std::string recvBuffer_;
|
||||
// Requested data size to accumulate in recvBuffer_ before continue processing
|
||||
int requiredToRecv_;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Start internal worker thread with RunLoop and submit corresponding open handlers into it
|
||||
* Not blocking
|
||||
*/
|
||||
- (void)start {
|
||||
worker_thread_ = [[NSThread alloc] initWithBlock:^{
|
||||
@autoreleasepool {
|
||||
[self notifyState:RPCServerStatus_Launched];
|
||||
[self open];
|
||||
shouldKeepRunning = YES;
|
||||
while (shouldKeepRunning && [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
|
||||
beforeDate:[NSDate distantFuture]]);
|
||||
[self notifyState:RPCServerStatus_Stopped];
|
||||
}
|
||||
}];
|
||||
[worker_thread_ start];
|
||||
}
|
||||
|
||||
/*!
|
||||
* Send message to workel thread runloop to finish processing
|
||||
* Not blocking
|
||||
*/
|
||||
- (void)stop {
|
||||
if (worker_thread_ == nil) return;
|
||||
|
||||
[self performSelector:@selector(stop_) onThread:worker_thread_ withObject:nil waitUntilDone:NO];
|
||||
worker_thread_ = nil; // TODO: is it valid? may be better to do that inside NSThread?
|
||||
}
|
||||
|
||||
- (void)stop_ {
|
||||
[self close];
|
||||
shouldKeepRunning = NO;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Base implementation to setup i/o streams
|
||||
* Will connect to host and port specified in corresponding properties
|
||||
*/
|
||||
- (void)open {
|
||||
CFReadStreamRef readStream;
|
||||
CFWriteStreamRef writeStream;
|
||||
CFStreamCreatePairWithSocketToHost(NULL, (__bridge CFStringRef)self.host, self.port, &readStream,
|
||||
&writeStream);
|
||||
inputStream_ = (__bridge NSInputStream*)readStream;
|
||||
outputStream_ = (__bridge NSOutputStream*)writeStream;
|
||||
[inputStream_ setDelegate:self];
|
||||
[outputStream_ setDelegate:self];
|
||||
[inputStream_ scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
|
||||
[outputStream_ scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
|
||||
[outputStream_ open];
|
||||
[inputStream_ open];
|
||||
}
|
||||
|
||||
/*!
|
||||
* Base implementation to setup i/o streams
|
||||
* Will assign i/o streams to provided socket connection.
|
||||
*/
|
||||
- (void)openWithSocket:(CFSocketNativeHandle)sock {
|
||||
CFReadStreamRef readStream;
|
||||
CFWriteStreamRef writeStream;
|
||||
CFStreamCreatePairWithSocket(NULL, sock, &readStream, &writeStream);
|
||||
inputStream_ = (__bridge NSInputStream*)readStream;
|
||||
outputStream_ = (__bridge NSOutputStream*)writeStream;
|
||||
[inputStream_ setDelegate:self];
|
||||
[outputStream_ setDelegate:self];
|
||||
[inputStream_ scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
|
||||
[outputStream_ scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
|
||||
[outputStream_ open];
|
||||
[inputStream_ open];
|
||||
}
|
||||
|
||||
/*!
|
||||
* Close i/o streams associated with connection
|
||||
*/
|
||||
- (void)close {
|
||||
[inputStream_ close];
|
||||
[outputStream_ close];
|
||||
[inputStream_ removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
|
||||
[outputStream_ removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
|
||||
[inputStream_ setDelegate:nil];
|
||||
[outputStream_ setDelegate:nil];
|
||||
inputStream_ = nil;
|
||||
outputStream_ = nil;
|
||||
}
|
||||
|
||||
/// Unimplemented stubs
|
||||
- (bool)onReadHandler {
|
||||
return false;
|
||||
}
|
||||
- (bool)onWriteHandler {
|
||||
return false;
|
||||
}
|
||||
- (void)onEndEncountered {
|
||||
}
|
||||
|
||||
/*!
|
||||
* Try to read data from stream and call processing handler
|
||||
*/
|
||||
- (void)tryToRead {
|
||||
const int kBufferSize = 4 << 10; // 4kB buffer
|
||||
const int prev_size = recvBuffer_.size();
|
||||
recvBuffer_.resize(kBufferSize);
|
||||
size_t nbytes = [inputStream_ read:(uint8_t*)recvBuffer_.data() + prev_size
|
||||
maxLength:recvBuffer_.size() - prev_size];
|
||||
recvBuffer_.resize(nbytes + prev_size);
|
||||
|
||||
// feed while it accept or requested particulat buffer size
|
||||
while (!recvBuffer_.empty() && requiredToRecv_ <= recvBuffer_.size() && [self onReadHandler]);
|
||||
}
|
||||
|
||||
/*!
|
||||
* Try to write remaining data to stream and call processing handler
|
||||
*/
|
||||
- (void)tryToWrite {
|
||||
if (!sendBuffer_.empty()) {
|
||||
size_t nbytes = [outputStream_ write:(uint8_t*)sendBuffer_.data() maxLength:sendBuffer_.size()];
|
||||
sendBuffer_.erase(0, nbytes);
|
||||
}
|
||||
// call write handler while it want be called and space is available
|
||||
while (sendBuffer_.empty() && [outputStream_ hasSpaceAvailable] && [self onWriteHandler]);
|
||||
}
|
||||
|
||||
/*!
|
||||
* Main event handler of socket stream events
|
||||
*/
|
||||
- (void)stream:(NSStream*)strm handleEvent:(NSStreamEvent)event {
|
||||
std::string buffer;
|
||||
switch (event) {
|
||||
case NSStreamEventOpenCompleted: {
|
||||
// Nothing
|
||||
break;
|
||||
}
|
||||
case NSStreamEventHasBytesAvailable:
|
||||
if (strm == inputStream_) {
|
||||
[self tryToRead];
|
||||
if ([outputStream_ hasSpaceAvailable]) [self tryToWrite];
|
||||
}
|
||||
break;
|
||||
case NSStreamEventHasSpaceAvailable: {
|
||||
if (strm == outputStream_) {
|
||||
[self tryToWrite];
|
||||
if ([inputStream_ hasBytesAvailable]) [self tryToRead];
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NSStreamEventErrorOccurred: {
|
||||
[self notifyError:[strm streamError].localizedDescription];
|
||||
break;
|
||||
}
|
||||
case NSStreamEventEndEncountered: {
|
||||
[self onEndEncountered];
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
NSLog(@"Unknown event");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Helpers
|
||||
|
||||
/*!
|
||||
* Set buffer to send into stream. Try to send immediately or submit to lazy sending
|
||||
* Non blocking operation
|
||||
*/
|
||||
- (void)toSend:(NSData*)data {
|
||||
sendBuffer_.append(static_cast<const char*>(data.bytes), data.length);
|
||||
|
||||
// try to flush buffer
|
||||
NSInteger sent_size = [outputStream_ write:(uint8_t*)sendBuffer_.data()
|
||||
maxLength:sendBuffer_.size()];
|
||||
sendBuffer_.erase(0, sent_size);
|
||||
}
|
||||
|
||||
/*!
|
||||
* Set buffer to send in packet format [size, data]. Behaviour is same as for toSend.
|
||||
*/
|
||||
- (void)toSendPacked:(NSData*)data {
|
||||
uint32_t packet_size = data.length;
|
||||
[self toSend:[NSData dataWithBytes:&packet_size length:sizeof(packet_size)]];
|
||||
[self toSend:data];
|
||||
}
|
||||
|
||||
/*!
|
||||
*/
|
||||
- (NSData*)requestInputDataWithSize:(NSInteger)size {
|
||||
if (recvBuffer_.size() < size) {
|
||||
requiredToRecv_ = size;
|
||||
return nil;
|
||||
}
|
||||
NSData* res = [NSData dataWithBytes:recvBuffer_.data() length:size];
|
||||
recvBuffer_.erase(0, size);
|
||||
return res;
|
||||
}
|
||||
|
||||
/*!
|
||||
*/
|
||||
- (NSData*)requestInputDataPacked {
|
||||
uint32_t size;
|
||||
if (recvBuffer_.size() < sizeof(size)) {
|
||||
requiredToRecv_ = sizeof(size);
|
||||
return nil;
|
||||
}
|
||||
size = *(uint32_t*)recvBuffer_.data();
|
||||
if (recvBuffer_.size() < sizeof(size) + size) {
|
||||
requiredToRecv_ = sizeof(size) + size;
|
||||
return nil;
|
||||
}
|
||||
NSData* res = [NSData dataWithBytes:recvBuffer_.data() + sizeof(size) length:size];
|
||||
recvBuffer_.erase(0, sizeof(size) + size);
|
||||
return res;
|
||||
};
|
||||
|
||||
#pragma mark - Notifiers
|
||||
|
||||
/*!
|
||||
* Notify external listener about error.
|
||||
* Also print error message to std out in case of Verbose mode
|
||||
*/
|
||||
- (void)notifyError:(NSString*)msg {
|
||||
// Duplicate error message in std output. Host launcher script may listen it.
|
||||
if (self.verbose) NSLog(@"[IOS-RPC] ERROR: %@", msg);
|
||||
if (self.delegate) [self.delegate onError:msg];
|
||||
}
|
||||
|
||||
/*!
|
||||
* Notify external listener about server state changes.
|
||||
* Also print information to std out in case of Verbose mode
|
||||
*/
|
||||
- (void)notifyState:(RPCServerStatus)state {
|
||||
// Duplicate sattus changing in std output. Host launcher script may listen it.
|
||||
if (self.verbose) NSLog(@"[IOS-RPC] STATE: %d", state);
|
||||
if (self.delegate != nil) [self.delegate onStatusChanged:state];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@interface RPCServerProxy : RPCServerBase
|
||||
@end
|
||||
|
||||
typedef enum {
|
||||
RPCServerProxyState_Idle,
|
||||
RPCServerProxyState_HandshakeToSend,
|
||||
RPCServerProxyState_HandshakeToRecv,
|
||||
RPCServerProxyState_Processing,
|
||||
} RPCServerProxyState;
|
||||
|
||||
@implementation RPCServerProxy {
|
||||
/// Original TVM RPC event handler
|
||||
tvm::runtime::FEventHandler handler_;
|
||||
@protected
|
||||
/// Sate of Proxy client implementation
|
||||
RPCServerProxyState state_;
|
||||
}
|
||||
|
||||
- (instancetype)init {
|
||||
if (self = [super init]) {
|
||||
handler_ = nullptr;
|
||||
state_ = RPCServerProxyState_Idle;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Implement matching of internat state on state available for outside users
|
||||
*/
|
||||
- (void)setState:(RPCServerProxyState)new_state {
|
||||
// Send Connected notification because Proxy doesn't response until client connected.
|
||||
if (new_state == RPCServerProxyState_HandshakeToRecv)
|
||||
[self notifyState:RPCServerStatus_Connected];
|
||||
if (new_state == RPCServerProxyState_Idle) [self notifyState:RPCServerStatus_Disconnected];
|
||||
if (state_ == RPCServerProxyState_HandshakeToRecv && new_state == RPCServerProxyState_Processing)
|
||||
[self notifyState:RPCServerStatus_RPCSessionStarted];
|
||||
if (state_ == RPCServerProxyState_Processing && new_state == RPCServerProxyState_Idle)
|
||||
[self notifyState:RPCServerStatus_RPCSessionStarted];
|
||||
|
||||
state_ = new_state;
|
||||
}
|
||||
|
||||
- (bool)onWriteHandler {
|
||||
switch (state_) {
|
||||
case RPCServerProxyState_HandshakeToSend: {
|
||||
// Send together kRPCMagic and server descriptor because of Proxy
|
||||
int32_t code = tvm::runtime::kRPCMagic;
|
||||
[self toSend:[NSData dataWithBytes:&code length:sizeof(code)]];
|
||||
|
||||
std::string full_key = std::string("server:") + self.key.UTF8String;
|
||||
[self toSendPacked:[NSData dataWithBytes:full_key.data() length:full_key.size()]];
|
||||
|
||||
self.state = RPCServerProxyState_HandshakeToRecv;
|
||||
return TRUE;
|
||||
}
|
||||
case RPCServerProxyState_Processing: {
|
||||
try {
|
||||
TVMByteArray dummy{nullptr, 0};
|
||||
int flag = handler_(dummy, 2);
|
||||
if (flag == 0) {
|
||||
[self onEndEncountered];
|
||||
}
|
||||
return flag == 2;
|
||||
} catch (const tvm::Error& e) {
|
||||
[self close];
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// Nothing
|
||||
break;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
- (bool)onReadHandler {
|
||||
switch (state_) {
|
||||
case RPCServerProxyState_HandshakeToRecv: {
|
||||
int32_t code = tvm::runtime::kRPCMagic;
|
||||
NSData* data = [self requestInputDataWithSize:sizeof(code)];
|
||||
if (data == nil) return FALSE;
|
||||
|
||||
if (*(int32_t*)data.bytes != tvm::runtime::kRPCMagic) {
|
||||
[self notifyError:@"Wrong response, is not RPC client."];
|
||||
[self close];
|
||||
return FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
handler_ = tvm::runtime::CreateServerEventHandler(outputStream_, "iphone", "%toinit");
|
||||
|
||||
self.state = RPCServerProxyState_Processing;
|
||||
return TRUE;
|
||||
break;
|
||||
}
|
||||
case RPCServerProxyState_Processing: {
|
||||
int flag = 1;
|
||||
if ([outputStream_ hasSpaceAvailable]) {
|
||||
flag |= 2;
|
||||
}
|
||||
// always try to write
|
||||
try {
|
||||
TVMByteArray arr{recvBuffer_.data(), recvBuffer_.size()};
|
||||
flag = handler_(arr, flag);
|
||||
recvBuffer_.clear();
|
||||
if (flag == 0) {
|
||||
[self onEndEncountered];
|
||||
}
|
||||
return flag == 1;
|
||||
} catch (const tvm::Error& e) {
|
||||
[self close];
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// Nothing
|
||||
break;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
- (void)onEndEncountered {
|
||||
// Automatic reconnection when session is finished.
|
||||
[self close];
|
||||
[self open];
|
||||
}
|
||||
|
||||
- (void)open {
|
||||
[super open];
|
||||
self.state = RPCServerProxyState_HandshakeToSend;
|
||||
}
|
||||
|
||||
- (void)close {
|
||||
[super close];
|
||||
handler_ = nullptr;
|
||||
self.state = RPCServerProxyState_Idle;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@interface RPCServerStandalone : RPCServerProxy
|
||||
@property(readonly) int rpc_port;
|
||||
@end
|
||||
|
||||
@implementation RPCServerStandalone {
|
||||
// Socket to listen incoming connections
|
||||
CFSocketRef socket_;
|
||||
/// Current socket connection handler
|
||||
CFSocketNativeHandle connection_;
|
||||
/// Port range to try bind to socket
|
||||
int port_range_start;
|
||||
int port_range_end;
|
||||
}
|
||||
|
||||
- (instancetype)init {
|
||||
if (self = [super init]) {
|
||||
connection_ = 0;
|
||||
port_range_start = 9090;
|
||||
port_range_end = 9099;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setState:(RPCServerProxyState)new_state {
|
||||
if (state_ == RPCServerProxyState_Idle && new_state == RPCServerProxyState_HandshakeToSend) {
|
||||
self.actual_port = _rpc_port;
|
||||
self.device_addr = [NSString stringWithUTF8String:tvm::runtime::getWiFiAddress().c_str()];
|
||||
if (self.verbose) {
|
||||
// Notify host runner script with actual address
|
||||
NSLog(@"[IOS-RPC] IP: %s", tvm::runtime::getWiFiAddress().c_str());
|
||||
NSLog(@"[IOS-RPC] PORT: %d", _rpc_port);
|
||||
}
|
||||
[self notifyState:RPCServerStatus_Connected];
|
||||
}
|
||||
if (new_state == RPCServerProxyState_Idle) [self notifyState:RPCServerStatus_Disconnected];
|
||||
if (state_ == RPCServerProxyState_HandshakeToRecv && new_state == RPCServerProxyState_Processing)
|
||||
[self notifyState:RPCServerStatus_RPCSessionStarted];
|
||||
if (state_ == RPCServerProxyState_Processing && new_state == RPCServerProxyState_HandshakeToSend)
|
||||
[self notifyState:RPCServerStatus_RPCSessionFinished];
|
||||
|
||||
state_ = new_state;
|
||||
}
|
||||
|
||||
- (void)handleConnect:(CFSocketNativeHandle)hdl {
|
||||
connection_ = hdl;
|
||||
[super openWithSocket:connection_];
|
||||
self.state = RPCServerProxyState_HandshakeToSend;
|
||||
}
|
||||
|
||||
static void handleConnect(CFSocketRef socket, CFSocketCallBackType type, CFDataRef address,
|
||||
const void* data, void* info) {
|
||||
RPCServerStandalone* it = (__bridge RPCServerStandalone*)(info);
|
||||
[it handleConnect:*static_cast<const CFSocketNativeHandle*>(data)];
|
||||
}
|
||||
|
||||
- (void)open {
|
||||
CFSocketContext ctx{};
|
||||
ctx.info = (__bridge void*)self;
|
||||
|
||||
socket_ = CFSocketCreate(kCFAllocatorDefault, PF_INET, SOCK_STREAM, IPPROTO_TCP,
|
||||
kCFSocketAcceptCallBack, handleConnect, &ctx);
|
||||
self->_rpc_port = 0;
|
||||
|
||||
// Try to bind with range
|
||||
for (int port = port_range_start; port < port_range_end; port++) {
|
||||
struct sockaddr_in sin;
|
||||
memset(&sin, 0, sizeof(sin));
|
||||
sin.sin_len = sizeof(sin);
|
||||
sin.sin_family = AF_INET;
|
||||
sin.sin_port = htons(port);
|
||||
sin.sin_addr.s_addr = INADDR_ANY;
|
||||
|
||||
CFDataRef sincfd = CFDataCreate(kCFAllocatorDefault, (UInt8*)&sin, sizeof(sin));
|
||||
CFSocketError res = CFSocketSetAddress(socket_, sincfd);
|
||||
CFRelease(sincfd);
|
||||
if (res == kCFSocketSuccess) {
|
||||
self->_rpc_port = port;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (self->_rpc_port == 0) {
|
||||
@throw
|
||||
[NSException exceptionWithName:@"SocketError"
|
||||
reason:[NSString stringWithFormat:@"Unable bind socket to port"
|
||||
"in range [%d, %d]",
|
||||
port_range_start, port_range_end]
|
||||
userInfo:nil];
|
||||
}
|
||||
|
||||
CFRunLoopSourceRef socketsource = CFSocketCreateRunLoopSource(kCFAllocatorDefault, socket_, 0);
|
||||
CFRunLoopAddSource(CFRunLoopGetCurrent(), socketsource, kCFRunLoopDefaultMode);
|
||||
|
||||
self.state = RPCServerProxyState_HandshakeToSend;
|
||||
}
|
||||
|
||||
- (void)closeSocket {
|
||||
CFSocketInvalidate(socket_);
|
||||
}
|
||||
|
||||
- (void)close {
|
||||
[super close];
|
||||
close(connection_);
|
||||
}
|
||||
|
||||
- (void)onEndEncountered {
|
||||
[self close];
|
||||
[self notifyState:RPCServerStatus_RPCSessionFinished];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@interface RPCServerTracker : RPCServerBase <RPCServerEventListener>
|
||||
@end
|
||||
|
||||
typedef enum {
|
||||
RPCServerTracker_Idle,
|
||||
RPCServerTracker_HandshakeToSend,
|
||||
RPCServerTracker_HandshakeToRecv,
|
||||
RPCServerTracker_ServerInfoToSend,
|
||||
RPCServerTracker_ServerInfoToRecv,
|
||||
RPCServerTracker_ReportResToSend,
|
||||
RPCServerTracker_ReportResToRecv,
|
||||
RPCServerTracker_UpdateKeyToSend,
|
||||
RPCServerTracker_UpdateKeyToRecv,
|
||||
RPCServerTracker_WaitConnection
|
||||
} RPCServerTrackerState;
|
||||
|
||||
@implementation RPCServerTracker {
|
||||
RPCServerTrackerState state_;
|
||||
RPCServerStandalone* rpc_server_;
|
||||
}
|
||||
|
||||
- (void)setState:(RPCServerTrackerState)new_state {
|
||||
if (state_ == RPCServerTracker_ReportResToRecv && new_state == RPCServerTracker_WaitConnection)
|
||||
[self notifyState:RPCServerStatus_Connected];
|
||||
if (state_ == RPCServerTracker_WaitConnection && new_state == RPCServerTracker_Idle)
|
||||
[self notifyState:RPCServerStatus_Disconnected];
|
||||
|
||||
state_ = new_state;
|
||||
}
|
||||
|
||||
- (bool)onWriteHandler {
|
||||
switch (state_) {
|
||||
case RPCServerTracker_HandshakeToSend: {
|
||||
int32_t code = tvm::runtime::kRPCTrackerMagic;
|
||||
[self toSend:[NSData dataWithBytes:&code length:sizeof(code)]];
|
||||
self.state = RPCServerTracker_HandshakeToRecv;
|
||||
return TRUE;
|
||||
break;
|
||||
}
|
||||
case RPCServerTracker_ServerInfoToSend: {
|
||||
std::ostringstream ss;
|
||||
ss << "[" << static_cast<int>(tvm::runtime::TrackerCode::kUpdateInfo)
|
||||
<< ", {\"key\": \"server:" << self.key.UTF8String << "\", \"addr\": ["
|
||||
<< self.custom_addr.UTF8String << ", \"" << self.port << "\"]}]";
|
||||
std::string data_s = ss.str();
|
||||
[self toSendPacked:[NSData dataWithBytes:data_s.data() length:data_s.length()]];
|
||||
self.state = RPCServerTracker_ServerInfoToRecv;
|
||||
return TRUE;
|
||||
break;
|
||||
}
|
||||
case RPCServerTracker_ReportResToSend: {
|
||||
std::mt19937 gen(std::random_device{}());
|
||||
std::uniform_real_distribution<float> dis(0.0, 1.0);
|
||||
|
||||
std::string address_to_report = "null";
|
||||
if (self.custom_addr != nil && self.custom_addr.length != 0) {
|
||||
address_to_report = self.custom_addr.UTF8String;
|
||||
}
|
||||
|
||||
std::string matchkey = std::string(self.key.UTF8String) + ":" + std::to_string(dis(gen));
|
||||
std::ostringstream ss;
|
||||
ss << "[" << static_cast<int>(tvm::runtime::TrackerCode::kPut) << ", \""
|
||||
<< self.key.UTF8String << "\", [" << rpc_server_.rpc_port << ", \"" << matchkey << "\"], "
|
||||
<< address_to_report << "]";
|
||||
|
||||
std::string data_s = ss.str();
|
||||
[self toSendPacked:[NSData dataWithBytes:data_s.data() length:data_s.length()]];
|
||||
self.state = RPCServerTracker_ReportResToRecv;
|
||||
return TRUE;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// Nothing
|
||||
break;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
- (bool)onReadHandler {
|
||||
static const std::string resp_OK =
|
||||
std::to_string(static_cast<int>(tvm::runtime::TrackerCode::kSuccess));
|
||||
switch (state_) {
|
||||
case RPCServerTracker_HandshakeToRecv: {
|
||||
NSData* data = [self requestInputDataWithSize:sizeof(int)];
|
||||
if (data == nil) return FALSE;
|
||||
|
||||
if (*(int*)data.bytes != tvm::runtime::kRPCTrackerMagic) {
|
||||
[self notifyError:@"Wrong response, is not RPC Tracker."];
|
||||
[self close];
|
||||
return FALSE;
|
||||
break;
|
||||
}
|
||||
self.state = RPCServerTracker_ServerInfoToSend;
|
||||
return TRUE;
|
||||
break;
|
||||
}
|
||||
case RPCServerTracker_ServerInfoToRecv: {
|
||||
NSData* data = [self requestInputDataPacked];
|
||||
if (data == nil) return FALSE;
|
||||
|
||||
if (std::string((char*)data.bytes, data.length) != resp_OK) {
|
||||
[self notifyError:@"Failed to Update info on tracker. Response is not OK."];
|
||||
[self close];
|
||||
return FALSE;
|
||||
break;
|
||||
}
|
||||
self.state = RPCServerTracker_ReportResToSend;
|
||||
return TRUE;
|
||||
break;
|
||||
}
|
||||
case RPCServerTracker_ReportResToRecv: {
|
||||
NSData* data = [self requestInputDataPacked];
|
||||
if (data == nil) return FALSE;
|
||||
|
||||
if (std::string((char*)data.bytes, data.length) != resp_OK) {
|
||||
[self notifyError:@"Failed to Put server into tracker. Response is not OK."];
|
||||
[self close];
|
||||
return FALSE;
|
||||
break;
|
||||
}
|
||||
self.state = RPCServerTracker_WaitConnection;
|
||||
return TRUE;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// Nothing
|
||||
break;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
- (void)onEndEncountered {
|
||||
[self close];
|
||||
}
|
||||
|
||||
- (void)close {
|
||||
[rpc_server_ close];
|
||||
[rpc_server_ closeSocket];
|
||||
[super close];
|
||||
self.state = RPCServerTracker_Idle;
|
||||
}
|
||||
|
||||
- (void)open {
|
||||
// Start internal Standalone RPC server at first
|
||||
rpc_server_ = [[RPCServerStandalone alloc] init];
|
||||
rpc_server_.key = self.key;
|
||||
rpc_server_.delegate = self;
|
||||
[rpc_server_ open];
|
||||
|
||||
[super open];
|
||||
self.state = RPCServerTracker_HandshakeToSend;
|
||||
}
|
||||
|
||||
- (void)onError:(NSString*)msg {
|
||||
// transfer error form internal rpc_server_ to real delegate
|
||||
[self notifyError:msg];
|
||||
}
|
||||
|
||||
- (void)onStatusChanged:(RPCServerStatus)status {
|
||||
if (status == RPCServerStatus_RPCSessionFinished) {
|
||||
[self notifyState:status];
|
||||
self.state = RPCServerTracker_ReportResToSend;
|
||||
[self tryToWrite];
|
||||
}
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation RPCServer
|
||||
|
||||
+ (instancetype)serverWithMode:(RPCServerMode)mode {
|
||||
if (mode == RPCServerMode_Standalone) return [[RPCServerStandalone alloc] init];
|
||||
if (mode == RPCServerMode_Proxy) return [[RPCServerProxy alloc] init];
|
||||
if (mode == RPCServerMode_Tracker) return [[RPCServerTracker alloc] init];
|
||||
return nil;
|
||||
}
|
||||
|
||||
/// Unimplemented stubs
|
||||
- (void)start {
|
||||
}
|
||||
- (void)stop {
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \file TVMRuntime.mm
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#include <tvm/ffi/function.h>
|
||||
#include <tvm/ffi/reflection/registry.h>
|
||||
|
||||
#include "RPCArgs.h"
|
||||
|
||||
// internal TVM header
|
||||
#include <../../../src/runtime/file_utils.h>
|
||||
|
||||
#if defined(USE_CUSTOM_DSO_LOADER) && USE_CUSTOM_DSO_LOADER == 1
|
||||
// internal TVM header to achieve Library class
|
||||
#include <../../../3rdparty/tvm-ffi/src/ffi/extra/library_module.h>
|
||||
#include <custom_dlfcn.h>
|
||||
#endif
|
||||
|
||||
namespace tvm {
|
||||
namespace runtime {
|
||||
namespace detail {
|
||||
|
||||
// Override logging mechanism
|
||||
[[noreturn]] void LogFatalImpl(const std::string& file, int lineno, const std::string& message) {
|
||||
throw tvm::runtime::InternalError(file, lineno, message);
|
||||
}
|
||||
|
||||
void LogMessageImpl(const std::string& file, int lineno, int level, const std::string& message) {
|
||||
NSLog(@"%s:%d: %s", file.c_str(), lineno, message.c_str());
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
TVM_FFI_STATIC_INIT_BLOCK() {
|
||||
namespace refl = tvm::ffi::reflection;
|
||||
refl::GlobalDef()
|
||||
.def_packed("tvm.rpc.server.workpath",
|
||||
[](ffi::PackedArgs args, ffi::Any* rv) {
|
||||
static const std::string base_ = NSTemporaryDirectory().UTF8String;
|
||||
const auto path = args[0].cast<std::string>();
|
||||
*rv = base_ + "/" + path;
|
||||
})
|
||||
.def_packed("tvm.rpc.server.load_module", [](ffi::PackedArgs args, ffi::Any* rv) {
|
||||
auto name = args[0].cast<std::string>();
|
||||
std::string fmt = GetFileFormat(name, "");
|
||||
NSString* base;
|
||||
if (fmt == "dylib") {
|
||||
// only load dylib from frameworks.
|
||||
NSBundle* bundle = [NSBundle mainBundle];
|
||||
base = [[bundle privateFrameworksPath] stringByAppendingPathComponent:@"tvm"];
|
||||
|
||||
if (tvm::ffi::Function::GetGlobal("ffi.Module.load_from_file.dylib_custom")) {
|
||||
// Custom dso loader is present. Will use it.
|
||||
base = NSTemporaryDirectory();
|
||||
fmt = "dylib_custom";
|
||||
}
|
||||
} else {
|
||||
// Load other modules in tempdir.
|
||||
base = NSTemporaryDirectory();
|
||||
}
|
||||
NSString* path =
|
||||
[base stringByAppendingPathComponent:[NSString stringWithUTF8String:name.c_str()]];
|
||||
name = [path UTF8String];
|
||||
*rv = Module::LoadFromFile(name, fmt);
|
||||
LOG(INFO) << "Load module from " << name << " ...";
|
||||
});
|
||||
}
|
||||
|
||||
#if defined(USE_CUSTOM_DSO_LOADER) && USE_CUSTOM_DSO_LOADER == 1
|
||||
|
||||
// Custom dynamic library loader. Supports unsigned binary
|
||||
class UnsignedDSOLoader final : public Library {
|
||||
public:
|
||||
~UnsignedDSOLoader() {
|
||||
if (lib_handle_) {
|
||||
custom_dlclose(lib_handle_);
|
||||
lib_handle_ = nullptr;
|
||||
};
|
||||
}
|
||||
void Init(const std::string& name) {
|
||||
lib_handle_ = custom_dlopen(name.c_str(), RTLD_NOW | RTLD_LOCAL);
|
||||
TVM_FFI_ICHECK(lib_handle_ != nullptr)
|
||||
<< "Failed to load dynamic shared library " << name << " " << custom_dlerror();
|
||||
}
|
||||
|
||||
void* GetSymbol(const char* name) final { return custom_dlsym(lib_handle_, name); }
|
||||
|
||||
private:
|
||||
// Library handle
|
||||
void* lib_handle_{nullptr};
|
||||
};
|
||||
|
||||
// Add UnsignedDSOLoader plugin in global registry
|
||||
TVM_FFI_STATIC_INIT_BLOCK() {
|
||||
namespace refl = tvm::ffi::reflection;
|
||||
refl::GlobalDef().def_packed("ffi.Module.load_from_file.dylib_custom",
|
||||
[](ffi::PackedArgs args, ffi::Any* rv) {
|
||||
auto n = ffi::make_object<UnsignedDSOLoader>();
|
||||
n->Init(args[0]);
|
||||
*rv = tvm::ffi::CreateLibraryModule(n);
|
||||
});
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace runtime
|
||||
} // namespace tvm
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \file ViewController.h
|
||||
*/
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "RPCServer.h"
|
||||
|
||||
@interface ViewController : UIViewController <RPCServerEventListener, UITextFieldDelegate>
|
||||
|
||||
@property(weak, nonatomic) IBOutlet UITextField* proxyURL;
|
||||
@property(weak, nonatomic) IBOutlet UITextField* proxyPort;
|
||||
@property(weak, nonatomic) IBOutlet UITextField* proxyKey;
|
||||
@property(weak, nonatomic) IBOutlet UILabel* statusLabel;
|
||||
@property(weak, nonatomic) IBOutlet UITextView* infoText;
|
||||
|
||||
- (IBAction)connect:(id)sender;
|
||||
@property(retain, nonatomic) IBOutlet UIButton* ConnectButton;
|
||||
@property(retain, nonatomic) IBOutlet UISegmentedControl* ModeSelector;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,169 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \file ViewController.mm
|
||||
*/
|
||||
|
||||
#import "ViewController.h"
|
||||
#import "RPCArgs.h"
|
||||
|
||||
@implementation ViewController {
|
||||
// server implementation
|
||||
RPCServer* server_;
|
||||
// Button state. True - push will start connection, false - push will disconnect
|
||||
bool to_connect_;
|
||||
}
|
||||
|
||||
- (void)viewDidLoad {
|
||||
// To handle end editing events
|
||||
self.proxyURL.delegate = self;
|
||||
self.proxyPort.delegate = self;
|
||||
self.proxyKey.delegate = self;
|
||||
|
||||
RPCArgs args = get_current_rpc_args();
|
||||
self.proxyURL.text = @(args.host_url);
|
||||
self.proxyPort.text = @(args.host_port).stringValue;
|
||||
self.proxyKey.text = @(args.key);
|
||||
|
||||
self.ModeSelector.selectedSegmentIndex = args.server_mode;
|
||||
self->to_connect_ = true;
|
||||
|
||||
// Add border to button
|
||||
void (^addBorder)(UIButton* btn) = ^(UIButton* btn) {
|
||||
btn.layer.borderWidth = 2.0f;
|
||||
btn.layer.borderColor = self.ConnectButton.currentTitleColor.CGColor;
|
||||
btn.layer.cornerRadius = 10;
|
||||
};
|
||||
addBorder(self.ConnectButton);
|
||||
|
||||
// Connect to tracker immediately
|
||||
if (args.immediate_connect) {
|
||||
[self disableUIInteraction];
|
||||
[self open];
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Disable all UI elements
|
||||
*/
|
||||
- (void)disableUIInteraction {
|
||||
void (^disable)(UITextField* field) = ^(UITextField* field) {
|
||||
field.enabled = NO;
|
||||
field.backgroundColor = [UIColor lightGrayColor];
|
||||
};
|
||||
|
||||
void (^disableButton)(UIButton* btn) = ^(UIButton* btn) {
|
||||
btn.enabled = NO;
|
||||
btn.layer.borderColor = btn.currentTitleColor.CGColor;
|
||||
};
|
||||
|
||||
disable(self.proxyURL);
|
||||
disable(self.proxyPort);
|
||||
disable(self.proxyKey);
|
||||
disableButton(self.ConnectButton);
|
||||
self.ModeSelector.enabled = NO;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Start RPC server
|
||||
*/
|
||||
- (void)open {
|
||||
RPCArgs args = get_current_rpc_args();
|
||||
|
||||
RPCServerMode server_mode = static_cast<RPCServerMode>(self.ModeSelector.selectedSegmentIndex);
|
||||
|
||||
server_ = [RPCServer serverWithMode:server_mode];
|
||||
server_.host = self.proxyURL.text;
|
||||
server_.port = self.proxyPort.text.intValue;
|
||||
server_.key = self.proxyKey.text;
|
||||
server_.custom_addr = [NSString stringWithUTF8String:args.custom_addr];
|
||||
server_.verbose = args.verbose;
|
||||
server_.delegate = self;
|
||||
|
||||
[server_ start];
|
||||
|
||||
self.infoText.text = @"";
|
||||
self.statusLabel.text = @"Connecting...";
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Stop RPC server
|
||||
*/
|
||||
- (void)close {
|
||||
[server_ stop];
|
||||
self.statusLabel.text = @"Disconnecting...";
|
||||
}
|
||||
|
||||
#pragma mark - Button responders
|
||||
/*!
|
||||
* \brief Connect/disconnect button handler
|
||||
*/
|
||||
- (IBAction)connect:(id)sender {
|
||||
[[self view] endEditing:YES]; // to hide keyboard
|
||||
(to_connect_ ^= true) ? [self close] : [self open];
|
||||
[self.ConnectButton setTitle:to_connect_ ? @"Connect" : @"Disconenct"
|
||||
forState:UIControlStateNormal];
|
||||
}
|
||||
|
||||
#pragma mark - UITextFieldDelegate
|
||||
|
||||
- (BOOL)textFieldShouldReturn:(UITextField*)textField {
|
||||
[[self view] endEditing:YES]; // to hide keyboard on ret key
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
- (void)textFieldDidEndEditing:(UITextField*)textField {
|
||||
// Update values in app arg cache
|
||||
RPCArgs args = get_current_rpc_args();
|
||||
args.host_url = [self.proxyURL.text UTF8String];
|
||||
args.host_port = [self.proxyPort.text intValue];
|
||||
args.key = [self.proxyKey.text UTF8String];
|
||||
set_current_rpc_args(args);
|
||||
}
|
||||
|
||||
#pragma mark - RPCServerEvenlListener
|
||||
|
||||
- (void)onError:(NSString*)msg {
|
||||
dispatch_sync(dispatch_get_main_queue(), ^{
|
||||
self.infoText.text = [NSString stringWithFormat:@"Error: %@", msg];
|
||||
});
|
||||
}
|
||||
|
||||
- (void)onStatusChanged:(RPCServerStatus)status {
|
||||
dispatch_sync(dispatch_get_main_queue(), ^{
|
||||
switch (status) {
|
||||
case RPCServerStatus_Connected:
|
||||
if (self.ModeSelector.selectedSegmentIndex == RPCServerMode_Standalone) {
|
||||
self.infoText.text = [NSString
|
||||
stringWithFormat:@"IP: %@\nPort: %d", server_.device_addr, server_.actual_port];
|
||||
}
|
||||
self.statusLabel.text = @"Connected";
|
||||
break;
|
||||
case RPCServerStatus_Disconnected:
|
||||
self.statusLabel.text = @"Disconnected";
|
||||
break;
|
||||
default:
|
||||
// Nothing
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \file main.m
|
||||
*/
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "AppDelegate.h"
|
||||
#import "RPCArgs.h"
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
update_rpc_args(argc, argv);
|
||||
@autoreleasepool {
|
||||
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
<!--- Licensed to the Apache Software Foundation (ASF) under one -->
|
||||
<!--- or more contributor license agreements. See the NOTICE file -->
|
||||
<!--- distributed with this work for additional information -->
|
||||
<!--- regarding copyright ownership. The ASF licenses this file -->
|
||||
<!--- to you under the Apache License, Version 2.0 (the -->
|
||||
<!--- "License"); you may not use this file except in compliance -->
|
||||
<!--- with the License. You may obtain a copy of the License at -->
|
||||
|
||||
<!--- http://www.apache.org/licenses/LICENSE-2.0 -->
|
||||
|
||||
<!--- Unless required by applicable law or agreed to in writing, -->
|
||||
<!--- software distributed under the License is distributed on an -->
|
||||
<!--- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -->
|
||||
<!--- KIND, either express or implied. See the License for the -->
|
||||
<!--- specific language governing permissions and limitations -->
|
||||
<!--- under the License. -->
|
||||
|
||||
# Apache TVM Continuous Integration (CI)
|
||||
|
||||
## Overview
|
||||
|
||||
TVM's Continuous Integration is responsible for verifying the code in `apache/tvm` and testing PRs
|
||||
before they merge to inform TVM contributors and committers. These jobs are essential to keeping the
|
||||
TVM project in a healthy state and preventing breakages. CI in TVM is broken into these pieces:
|
||||
- Lint scripts in [`tests/lint`](../tests/lint).
|
||||
- The tests themselves, all of which live underneath [`tests`](../tests).
|
||||
- Definitions of test suites, with each suite defined as a separate `task_` script in
|
||||
[`tests/scripts`](../tests/scripts).
|
||||
- Scripts and automation [`ci/scripts`](../ci/scripts).
|
||||
- The linux test sequence (in [`Jenkinsfile`](../ci/jenkins/templates/)), which lints and builds TVM and runs test
|
||||
suites using Docker on Linux.
|
||||
- The Windows and Mac test sequences (in [`.github/actions`](../.github/actions)).
|
||||
- GitHub Actions that support the code review process (in [`.github/actions`](../.github/actions)).
|
||||
- Tools to reproduce the CI locally (in `tests/scripts`).
|
||||
- Infrastructure-as-Code that configures the cloud services that provide Jenkins for the TVM CI (in the
|
||||
[`tlc-pack/ci`](https://github.com/tlc-pack/ci) repo).
|
||||
|
||||
## CI Documentation Index
|
||||
|
||||
The CI documentation belongs with the implementation it describes. To make that concrete, the
|
||||
documentation is split like so:
|
||||
1. An overview of the CI is in this file.
|
||||
1. User-facing documentation lives in `apache/tvm`'s `docs/contribute` sub-directory and is served on the
|
||||
[TVM docs site](https://tvm.apache.org/docs/contribute/ci.html).
|
||||
2. Documentation of the tools that run TVM's various regression tests locally and the test suites
|
||||
are in this sub-directory.
|
||||
3. Documentation of the cloud services and their configuration lives in the
|
||||
[`tlc-pack/ci`](https://github.com/tlc-pack/ci) repo.
|
||||
|
||||
## Jenkins
|
||||
|
||||
Jenkins runs all of the Linux-based TVM CI-enabled regression tests. This includes tests against accelerated hardware such as GPUs. It excludes those regression tests that run against hardware not available in the cloud (those tests aren't currently exercised in TVM CI). The tests run by Jenkins represent most of the merge-blocking tests (and passing Jenkins should mostly correlate with passing the remaining Windows/Mac builds).
|
||||
|
||||
## GitHub Actions
|
||||
|
||||
GitHub Actions is used to run Windows jobs, MacOS jobs, and various on-GitHub automations. These are defined in [`.github/workflows`](../.github/workflows/). These automations include bots to:
|
||||
* [allow non-committers to merge approved / CI passing PRs](https://discuss.tvm.apache.org/t/rfc-allow-merging-via-pr-comments/12220)
|
||||
|
||||
https://github.com/apache/tvm/actions has the logs for each of these workflows. Note that when debugging these workflows changes from PRs from forked repositories won't be reflected in the PR. These should be tested in the forked repository first and linked in the PR body.
|
||||
|
||||
## Docker Images
|
||||
|
||||
Each CI job runs most of its work inside a Docker container, built from files
|
||||
in the [`docker/`](../docker) folder. These
|
||||
files are built nightly in Jenkins via the [tvm-docker](https://ci.tlcpack.ai/job/tvm-docker/) job.
|
||||
The images for these containers are hosted in the [tlcpack Docker Hub](https://hub.docker.com/u/tlcpack)
|
||||
and referenced in the [`jenkins/templates`](/ci/jenkins/templates/). These can be inspected and run
|
||||
locally via standard Docker commands.
|
||||
|
||||
### `ci-docker-staging`
|
||||
|
||||
The [ci-docker-staging](https://github.com/apache/tvm/tree/ci-docker-staging)
|
||||
branch is used to test updates to Docker images and `Jenkinsfile` changes. When
|
||||
running a build for a normal PR from a forked repository, Jenkins uses the code
|
||||
from the PR except for the `Jenkinsfile` itself, which comes from the base branch.
|
||||
When branches are built, the `Jenkinsfile` in the branch is used, so a committer
|
||||
with write access must push PRs to a branch in apache/tvm to properly test
|
||||
`Jenkinsfile` changes. If your PR makes changes to the `Jenkinsfile`, make sure
|
||||
to @ a [committer](/CONTRIBUTORS.md)
|
||||
and ask them to push your PR as a branch to test the changes.
|
||||
|
||||
# Jenkins CI
|
||||
|
||||
TVM uses Jenkins for running Linux continuous integration (CI) tests on
|
||||
[branches](https://ci.tlcpack.ai/job/tvm/) and
|
||||
[pull requests](https://ci.tlcpack.ai/job/tvm/view/change-requests/) through a
|
||||
build configuration specified in a [`Jenkinsfile`](/ci/jenkins/templates/).
|
||||
Other jobs run in GitHub Actions for Windows and MacOS jobs.
|
||||
|
||||
## `Jenkinsfile`
|
||||
|
||||
The template files in this directory are used to generate the [`Jenkinsfile`](/ci/jenkins/templates/) used by Jenkins to run CI jobs for each commit to PRs and branches.
|
||||
|
||||
To regenerate the `Jenkinsfile`, run `make` in the `ci/jenkins` dir.
|
||||
@@ -0,0 +1 @@
|
||||
/_venv
|
||||
@@ -0,0 +1,55 @@
|
||||
<!--- Licensed to the Apache Software Foundation (ASF) under one -->
|
||||
<!--- or more contributor license agreements. See the NOTICE file -->
|
||||
<!--- distributed with this work for additional information -->
|
||||
<!--- regarding copyright ownership. The ASF licenses this file -->
|
||||
<!--- to you under the Apache License, Version 2.0 (the -->
|
||||
<!--- "License"); you may not use this file except in compliance -->
|
||||
<!--- with the License. You may obtain a copy of the License at -->
|
||||
|
||||
<!--- http://www.apache.org/licenses/LICENSE-2.0 -->
|
||||
|
||||
<!--- Unless required by applicable law or agreed to in writing, -->
|
||||
<!--- software distributed under the License is distributed on an -->
|
||||
<!--- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -->
|
||||
<!--- KIND, either express or implied. See the License for the -->
|
||||
<!--- specific language governing permissions and limitations -->
|
||||
<!--- under the License. -->
|
||||
|
||||
# TVM CI
|
||||
|
||||
TVM runs CI jobs on every commit to an open pull request and to branches in the apache/tvm repo (such as `main`). These jobs are essential to keeping the TVM project in a healthy state and preventing breakages.
|
||||
|
||||
## Jenkins
|
||||
|
||||
Jenkins runs all of the linux-based TVM CI-enabled regression tests. This includes tests against accelerated hardware such as GPUs. It excludes those regression tests that run against hardware not available in the cloud (those tests aren't currently exercised in TVM CI). The tests run by Jenkins represent most of the merge-blocking tests (and passing Jenkins should mostly correlate with passing the remaining Windows/Mac builds).
|
||||
|
||||
## GitHub Actions
|
||||
|
||||
GitHub Actions is used to run Windows jobs, MacOS jobs, and various on-GitHub automations. These are defined in [`.github/workflows`](../../.github/workflows/). These automations include bots to:
|
||||
* [allow non-committers to merge approved / CI passing PRs](https://discuss.tvm.apache.org/t/rfc-allow-merging-via-pr-comments/12220)
|
||||
|
||||
https://github.com/apache/tvm/actions has the logs for each of these workflows. Note that when debugging these workflows changes from PRs from forked repositories won't be reflected in the PR. These should be tested in the forked repository first and linked in the PR body.
|
||||
|
||||
# Jenkins CI
|
||||
|
||||
TVM uses Jenkins for running Linux continuous integration (CI) tests on
|
||||
[branches](https://ci.tlcpack.ai/job/tvm/) and
|
||||
[pull requests](https://ci.tlcpack.ai/job/tvm/view/change-requests/) through a
|
||||
build configuration specified in a [`Jenkinsfile`](/ci/jenkins/templates/).
|
||||
Other jobs run in GitHub Actions for Windows and MacOS jobs.
|
||||
|
||||
## `Jenkinsfile`
|
||||
|
||||
The template files in this directory are used to generate the [`Jenkinsfile`](/ci/jenkins/templates/) used by Jenkins to run CI jobs for each commit to PRs and branches.
|
||||
|
||||
To regenerate the `Jenkinsfile`, run
|
||||
|
||||
```bash
|
||||
python3 -mvenv _venv
|
||||
_venv/bin/pip3 install -r ci/jenkins/requirements.txt
|
||||
_venv/bin/python3 ci/jenkins/generate.py
|
||||
```
|
||||
|
||||
# Infrastructure
|
||||
|
||||
While all TVM tests are contained within the apache/tvm repository, the infrastructure used to run the tests is donated by the TVM Community. To encourage collaboration, the configuration for TVM's CI infrastructure is stored in a public GitHub repository. TVM community members are encouraged to contribute improvements. The configuration, along with documentation of TVM's CI infrastructure, is in the [tlc-pack/ci](https://github.com/tlc-pack/ci) repo.
|
||||
@@ -0,0 +1,67 @@
|
||||
#!/usr/bin/env python3
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
"""Bundle registry for CI artifact stashing.
|
||||
|
||||
Single source of truth for the file lists uploaded to / downloaded from S3 by
|
||||
``ci/scripts/jenkins/s3.py``. This module deliberately carries nothing else —
|
||||
docker image tags live in ``ci/jenkins/docker-images.ini`` and Jinja-template
|
||||
metadata (image platforms, AWS endpoints) lives in ``ci/jenkins/generate.py``.
|
||||
|
||||
CLI: ``python3 ci/jenkins/data.py <bundle> [<bundle> ...]`` resolves bundle
|
||||
names to their file paths (one per line; exit 1 on unknown name). Used by
|
||||
``s3.py`` at Jenkins runtime and by any external caller that needs
|
||||
data-driven artifact lists.
|
||||
"""
|
||||
|
||||
import sys
|
||||
|
||||
files_to_stash = {
|
||||
# Executables and build files needed to run c++ tests
|
||||
"cpptest": ["build/cpptest", "build/build.ninja", "build/CMakeFiles/rules.ninja"],
|
||||
# runtime files
|
||||
"tvm_runtime": ["build/lib/libtvm_runtime.so", "build/config.cmake"],
|
||||
# compiler files
|
||||
"tvm_lib": [
|
||||
"build/lib/libtvm_compiler.so",
|
||||
"build/lib/libtvm_runtime.so",
|
||||
"build/lib/libtvm_ffi.so",
|
||||
"build/lib/libtvm_runtime_cuda.so",
|
||||
"build/lib/libtvm_runtime_vulkan.so",
|
||||
"build/lib/libtvm_runtime_opencl.so",
|
||||
"build/lib/libtvm_runtime_rocm.so",
|
||||
"build/lib/libtvm_runtime_extra.so",
|
||||
"build/libtvm_allvisible.so",
|
||||
"build/config.cmake",
|
||||
],
|
||||
# gpu related compiler files
|
||||
"tvm_lib_gpu_extra": [
|
||||
"build/3rdparty/libflash_attn/src/libflash_attn.so",
|
||||
"build/3rdparty/cutlass_fpA_intB_gemm/cutlass_kernels/libfpA_intB_gemm.so",
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
paths = []
|
||||
for name in sys.argv[1:]:
|
||||
if name not in files_to_stash:
|
||||
print(f"unknown bundle: {name}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
paths.extend(files_to_stash[name])
|
||||
for p in paths:
|
||||
print(p)
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user