Skip to content

Commit 40a542b

Browse files
tqchenShiboXing
authored andcommitted
[REFACTOR] Introduce and modernize FFI system (apache#17920)
This PR modernizes the FFI foundation of the project and introduce a new minimal and lightweight module [tvm ffi](https://github.com/apache/tvm/tree/refactor-s3/ffi) based on our lessons in the past few years. It implements a modern version of the [Unified Packed and Object RFC](https://github.com/apache/tvm-rfcs/blob/main/rfcs/0097-unify-packed-and-object.md) that unifies the packed function call and object systems. Summary of the change: - A dedicated clean Any/AnyView that can store strong and weak references of items - Function(previously PackedFunc) system built on top of the Any/AnyView - A minimal C API that backs the overall calls. We are stabilizing the API with a goal to bring clean, stable FFI conventions for both compiled and registered code - A rewrite of core python binding and generated code based on the module - Update existing code and test cases to the new module - Latest dlpack support The new module brings many benefits thanks to the cleaner design, to name a few: - Any can support both POD types(int) and object types. - Containers (e.g. Array) can now also contain Any value, e.g. now `Array<int>` is supported, no need for boxed types - Error handling now upgrades to object-based, allowing cleaner traceback across languages - Map now preserves insertion orders - Path toward isolated stabilize minimum core ABI/API foundation module - Type traits based design that cleanly defines how values interact with Any system - Automatic conversion of different types based on traits if needed Because FFI upgrade is at heart of the project, the change touches every component of the system. Importantly, this is an upgrade of the ABI so the change is not backward compatible. The code compiled under the old FFI won't work under the new one. We did provide example ABI translation (e.g. LegacyTVMArgValueToFFIAny) functions for compatibility. The PR tries to leave files in their old places while creating redirections. The goal is to have the first milestone landed and infrastructure in place, so we can do further refactors to complete features and cleanup legacy code as trackable PRs. As of now, python binding and compiled code are under the new convention while RPC and some other bindings still relies on legacy ABI translation. We will work on upgrades in the coming PRs, including areas such as reflection, phasing out legacy redirections etc.
1 parent ad42d42 commit 40a542b

File tree

925 files changed

+28150
-22679
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

925 files changed

+28150
-22679
lines changed

.github/workflows/main.yml

Lines changed: 52 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -49,22 +49,22 @@ jobs:
4949
run: >-
5050
conda build --output-folder=conda/pkg conda/recipe &&
5151
conda install tvm -c ./conda/pkg
52-
- name: Build iOS RPC
53-
run: |
54-
IOS_VERSION="14.0"
55-
CMAKE_FLAGS="-DCMAKE_BUILD_TYPE=Release \
56-
-DCMAKE_SYSTEM_NAME=iOS \
57-
-DCMAKE_SYSTEM_VERSION=${IOS_VERSION} \
58-
-DCMAKE_OSX_SYSROOT=iphonesimulator \
59-
-DCMAKE_OSX_ARCHITECTURES=x86_64 \
60-
-DCMAKE_OSX_DEPLOYMENT_TARGET=14.0 \
61-
-DCMAKE_BUILD_WITH_INSTALL_NAME_DIR=ON \
62-
-DUSE_IOS_RPC=ON"
63-
64-
mkdir build-ios-simulator
65-
cd build-ios-simulator
66-
cmake .. ${CMAKE_FLAGS}
67-
cmake --build . --target ios_rpc
52+
# - name: Build iOS RPC
53+
# run: |
54+
# IOS_VERSION="14.0"
55+
# CMAKE_FLAGS="-DCMAKE_BUILD_TYPE=Release \
56+
# -DCMAKE_SYSTEM_NAME=iOS \
57+
# -DCMAKE_SYSTEM_VERSION=${IOS_VERSION} \
58+
# -DCMAKE_OSX_SYSROOT=iphonesimulator \
59+
# -DCMAKE_OSX_ARCHITECTURES=x86_64 \
60+
# -DCMAKE_OSX_DEPLOYMENT_TARGET=14.0 \
61+
# -DCMAKE_BUILD_WITH_INSTALL_NAME_DIR=ON \
62+
# -DUSE_IOS_RPC=ON"
63+
#
64+
# mkdir build-ios-simulator
65+
# cd build-ios-simulator
66+
# cmake .. ${CMAKE_FLAGS}
67+
# cmake --build . --target ios_rpc
6868
- name: Test
6969
shell: bash -l {0}
7070
run: >-
@@ -108,74 +108,39 @@ jobs:
108108
run: >-
109109
python -m pytest -v tests/python/all-platform-minimal-test
110110
111-
# Disabled due to https://github.com/apache/tvm/issues/13950
112-
# Windows-Static-Runtime:
113-
# if: ${{ github.repository == 'apache/tvm' }}
114-
# runs-on: windows-2019
115-
# steps:
116-
# - uses: actions/checkout@v2
117-
# with:
118-
# submodules: 'recursive'
119-
# - name: Set up environment
120-
# uses: ./.github/actions/setup
121-
# - name: Build static TVM runtime
122-
# shell: bash -l {0}
123-
# run: |
124-
# tests/scripts/task_config_build_static.sh build
125-
# cd build
126-
# cmake .. -A x64 -DCMAKE_CONFIGURATION_TYPES="Release"
127-
# cmake --build . --config Release --target runtime
128-
129-
Linux-Static-Runtime:
130-
if: ${{ github.repository == 'apache/tvm' }}
131-
runs-on: ubuntu-latest
132-
steps:
133-
- uses: actions/checkout@v2
134-
with:
135-
submodules: 'recursive'
136-
- name: Set up environment
137-
uses: ./.github/actions/setup
138-
- name: Build static TVM runtime
139-
shell: bash -l {0}
140-
run: |
141-
tests/scripts/task_config_build_static.sh build
142-
cd build
143-
cmake ..
144-
cmake --build . --config Release --target runtime
145-
146-
Android:
147-
if: ${{ github.repository == 'apache/tvm' }}
148-
runs-on: ubuntu-22.04
149-
steps:
150-
- uses: actions/checkout@v2
151-
with:
152-
submodules: 'recursive'
153-
- name: Set up environment
154-
uses: ./.github/actions/setup
155-
- name: Set up java
156-
uses: actions/setup-java@v3
157-
with:
158-
distribution: 'zulu'
159-
java-version: '11'
160-
- name: Build TVM
161-
shell: bash -l {0}
162-
run: |
163-
mkdir build
164-
cd build
165-
../tests/scripts/task_config_build_jvm.sh .
166-
cmake ..
167-
make
168-
- name: Build TVM4J
169-
run: |
170-
make jvmpkg
171-
- name: Build android_rpc
172-
working-directory: apps/android_rpc
173-
run: |
174-
set -eux
175-
export PATH="${ANDROID_NDK_LATEST_HOME}:$PATH"
176-
gradle clean build
177-
- name: Upload android_rpc APK
178-
uses: actions/upload-artifact@v4
179-
with:
180-
name: android_rpc-debug.apk
181-
path: ./apps/android_rpc/app/build/outputs/apk/debug/app-debug.apk
111+
# Android:
112+
# if: ${{ github.repository == 'apache/tvm' }}
113+
# runs-on: ubuntu-22.04
114+
# steps:
115+
# - uses: actions/checkout@v2
116+
# with:
117+
# submodules: 'recursive'
118+
# - name: Set up environment
119+
# uses: ./.github/actions/setup
120+
# - name: Set up java
121+
# uses: actions/setup-java@v3
122+
# with:
123+
# distribution: 'zulu'
124+
# java-version: '11'
125+
# - name: Build TVM
126+
# shell: bash -l {0}
127+
# run: |
128+
# mkdir build
129+
# cd build
130+
# ../tests/scripts/task_config_build_jvm.sh .
131+
# cmake ..
132+
# make
133+
# - name: Build TVM4J
134+
# run: |
135+
# make jvmpkg
136+
# - name: Build android_rpc
137+
# working-directory: apps/android_rpc
138+
# run: |
139+
# set -eux
140+
# export PATH="${ANDROID_NDK_LATEST_HOME}:$PATH"
141+
# gradle clean build
142+
# - name: Upload android_rpc APK
143+
# uses: actions/upload-artifact@v4
144+
# with:
145+
# name: android_rpc-debug.apk
146+
# path: ./apps/android_rpc/app/build/outputs/apk/debug/app-debug.apk

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,6 @@
3131
[submodule "3rdparty/zlib"]
3232
path = 3rdparty/zlib
3333
url = https://github.com/madler/zlib.git
34+
[submodule "ffi/3rdparty/dlpack"]
35+
path = ffi/3rdparty/dlpack
36+
url = https://github.com/dmlc/dlpack.git

CMakeLists.txt

Lines changed: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,6 @@ if(MSVC)
159159
add_definitions(-D_SCL_SECURE_NO_WARNINGS)
160160
add_definitions(-D_ENABLE_EXTENDED_ALIGNED_STORAGE)
161161
add_definitions(-DNOMINMAX)
162-
163162
# regeneration does not work well with msbuild custom rules.
164163
set(CMAKE_SUPPRESS_REGENERATION ON)
165164
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /EHsc")
@@ -496,6 +495,9 @@ list(REMOVE_ITEM COMPILER_SRCS ${LIBINFO_FILE})
496495
add_library(tvm_objs OBJECT ${COMPILER_SRCS})
497496
add_library(tvm_runtime_objs OBJECT ${RUNTIME_SRCS})
498497
add_library(tvm_libinfo_objs OBJECT ${LIBINFO_FILE})
498+
target_link_libraries(tvm_objs PUBLIC tvm_ffi_header)
499+
target_link_libraries(tvm_runtime_objs PUBLIC tvm_ffi_header)
500+
target_link_libraries(tvm_libinfo_objs PUBLIC tvm_ffi_header)
499501

500502
include(GNUInstallDirs)
501503
if(NOT BUILD_DUMMY_LIBTVM)
@@ -567,6 +569,9 @@ if(USE_IOS_RPC)
567569
add_subdirectory("apps/ios_rpc")
568570
endif()
569571

572+
add_subdirectory(ffi)
573+
574+
570575
if(TVM_DEBUG_WITH_ABI_CHANGE)
571576
message(STATUS "Building with debug code that may cause ABI changes...")
572577
target_compile_definitions(tvm_objs PRIVATE "TVM_DEBUG_WITH_ABI_CHANGE")
@@ -602,6 +607,10 @@ endif()
602607
target_link_libraries(tvm PRIVATE ${TVM_RUNTIME_LINKER_LIBS})
603608
target_link_libraries(tvm_runtime PRIVATE ${TVM_RUNTIME_LINKER_LIBS})
604609

610+
target_link_libraries(tvm PUBLIC tvm_ffi_objs)
611+
target_link_libraries(tvm_runtime PUBLIC tvm_ffi_objs)
612+
613+
605614
if(BUILD_FOR_HEXAGON AND DEFINED USE_HEXAGON_GTEST AND EXISTS ${USE_HEXAGON_GTEST})
606615
include(FetchContent)
607616
FetchContent_Declare(googletest SOURCE_DIR "${USE_HEXAGON_GTEST}")
@@ -639,6 +648,7 @@ if (HIDE_PRIVATE_SYMBOLS AND NOT ${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
639648
target_link_libraries(tvm_runtime PRIVATE ${HIDE_SYMBOLS_LINKER_FLAGS})
640649
target_compile_definitions(tvm_allvisible PUBLIC $<TARGET_PROPERTY:tvm,INTERFACE_COMPILE_DEFINITONS>)
641650
target_compile_definitions(tvm_allvisible PRIVATE $<TARGET_PROPERTY:tvm,COMPILE_DEFINITONS>)
651+
target_link_libraries(tvm_allvisible PUBLIC tvm_ffi_objs)
642652
endif()
643653

644654
# Create the `cpptest` target if we can find GTest. If not, we create dummy
@@ -696,10 +706,10 @@ if(NOT DEFINED ENV{CONDA_BUILD})
696706
endif()
697707

698708
# Installation rules
699-
install(TARGETS tvm EXPORT ${PROJECT_NAME}Targets DESTINATION lib${LIB_SUFFIX})
700-
install(TARGETS tvm_runtime EXPORT ${PROJECT_NAME}Targets DESTINATION lib${LIB_SUFFIX})
709+
install(TARGETS tvm DESTINATION lib${LIB_SUFFIX})
710+
install(TARGETS tvm_runtime DESTINATION lib${LIB_SUFFIX})
701711
if(BUILD_FOR_HEXAGON AND DEFINED USE_HEXAGON_GTEST AND EXISTS ${USE_HEXAGON_GTEST})
702-
install(TARGETS gtest EXPORT ${PROJECT_NAME}Targets DESTINATION lib${LIB_SUFFIX})
712+
install(TARGETS gtest DESTINATION lib${LIB_SUFFIX})
703713
endif()
704714

705715
if (INSTALL_DEV)
@@ -734,9 +744,9 @@ string(APPEND PROJECT_CONFIG_CONTENT
734744
"include(\"\${CMAKE_CURRENT_LIST_DIR}/${PROJECT_NAME}Targets.cmake\")")
735745
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/temp_config_file.cmake" ${PROJECT_CONFIG_CONTENT})
736746

737-
install(EXPORT ${PROJECT_NAME}Targets
738-
NAMESPACE ${PROJECT_NAME}::
739-
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME})
747+
# install(EXPORT ${PROJECT_NAME}Targets
748+
# NAMESPACE ${PROJECT_NAME}::
749+
# DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME})
740750

741751
# Create config for find_package()
742752
configure_package_config_file(
@@ -750,9 +760,9 @@ install(
750760

751761
# More target definitions
752762
if(MSVC)
753-
target_compile_definitions(tvm_objs PRIVATE -DTVM_EXPORTS)
754-
target_compile_definitions(tvm_libinfo_objs PRIVATE -DTVM_EXPORTS)
755-
target_compile_definitions(tvm_runtime_objs PRIVATE -DTVM_EXPORTS)
763+
target_compile_definitions(tvm_objs PRIVATE -DTVM_EXPORTS -DTVM_FFI_EXPORTS)
764+
target_compile_definitions(tvm_libinfo_objs PRIVATE -DTVM_EXPORTS -DTVM_FFI_EXPORTS)
765+
target_compile_definitions(tvm_runtime_objs PRIVATE -DTVM_EXPORTS -DTVM_FFI_EXPORTS)
756766
endif()
757767

758768
set(TVM_IS_DEBUG_BUILD OFF)
@@ -774,17 +784,8 @@ if(TVM_IS_DEBUG_BUILD)
774784
endif()
775785
endif()
776786

777-
# Run dsymutil to generate debugging symbols for backtraces
778-
if(APPLE AND TVM_IS_DEBUG_BUILD)
779-
find_program(DSYMUTIL dsymutil)
780-
mark_as_advanced(DSYMUTIL)
781-
add_custom_command(TARGET tvm
782-
POST_BUILD
783-
COMMAND ${DSYMUTIL} ARGS $<TARGET_FILE:tvm>
784-
COMMENT "Running dsymutil"
785-
VERBATIM
786-
)
787-
endif()
787+
add_dsymutil(tvm)
788+
add_dsymutil(tvm_runtime)
788789

789790
if(BUILD_FOR_HEXAGON)
790791
# Wrap pthread_create to allow setting custom stack size.

apps/android_rpc/app/src/main/jni/Android.mk

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@ LOCAL_SRC_FILES := org_apache_tvm_native_c_api.cc
3737
LOCAL_LDFLAGS := -L$(SYSROOT)/usr/lib/ -llog
3838

3939
LOCAL_C_INCLUDES := $(ROOT_PATH)/include \
40-
$(ROOT_PATH)/3rdparty/dlpack/include \
40+
$(ROOT_PATH)/ffi/include \
41+
$(ROOT_PATH)/ffi/3rdparty/dlpack/include \
4142
$(ROOT_PATH)/3rdparty/dmlc-core/include \
4243
$(ROOT_PATH)/3rdparty/OpenCL-Headers
4344

apps/android_rpc/app/src/main/jni/tvm_runtime.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,16 @@
3232
* Android logcat.
3333
*/
3434
#define TVM_LOG_CUSTOMIZE 1
35+
#define TVM_FFI_USE_LIBBACKTRACE 0
3536

37+
#include "../ffi/src/ffi/container.cc"
38+
#include "../ffi/src/ffi/dtype.cc"
39+
#include "../ffi/src/ffi/error.cc"
40+
#include "../ffi/src/ffi/function.cc"
41+
#include "../ffi/src/ffi/ndarray.cc"
42+
#include "../ffi/src/ffi/object.cc"
43+
#include "../ffi/src/ffi/testing.cc"
44+
#include "../ffi/src/ffi/traceback.cc"
3645
#include "../src/runtime/c_runtime_api.cc"
3746
#include "../src/runtime/container.cc"
3847
#include "../src/runtime/cpu_device_api.cc"

apps/cpp_rpc/rpc_env.cc

Lines changed: 34 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -126,46 +126,44 @@ RPCEnv::RPCEnv(const std::string& wd) {
126126
mkdir(base_.c_str(), 0777);
127127
}
128128

129-
TVM_REGISTER_GLOBAL("tvm.rpc.server.workpath").set_body([this](TVMArgs args, TVMRetValue* rv) {
130-
*rv = this->GetPath(args[0]);
131-
});
129+
ffi::Function::SetGlobal(
130+
"tvm.rpc.server.workpath",
131+
ffi::Function::FromUnpacked([this](const std::string& path) { return this->GetPath(path); }));
132132

133-
TVM_REGISTER_GLOBAL("tvm.rpc.server.listdir").set_body([this](TVMArgs args, TVMRetValue* rv) {
134-
std::string dir = this->GetPath(args[0]);
135-
std::ostringstream os;
136-
for (auto d : ListDir(dir)) {
137-
os << d << ",";
138-
}
139-
*rv = os.str();
140-
});
141-
142-
TVM_REGISTER_GLOBAL("tvm.rpc.server.load_module").set_body([this](TVMArgs args, TVMRetValue* rv) {
143-
std::string file_name = this->GetPath(args[0]);
144-
file_name = BuildSharedLibrary(file_name);
145-
*rv = Module::LoadFromFile(file_name, "");
146-
LOG(INFO) << "Load module from " << file_name << " ...";
147-
});
133+
ffi::Function::SetGlobal("tvm.rpc.server.listdir",
134+
ffi::Function::FromUnpacked([this](const std::string& path) {
135+
std::string dir = this->GetPath(path);
136+
std::ostringstream os;
137+
for (auto d : ListDir(dir)) {
138+
os << d << ",";
139+
}
140+
return os.str();
141+
}));
148142

149-
TVM_REGISTER_GLOBAL("tvm.rpc.server.download_linked_module")
150-
.set_body([this](TVMArgs args, TVMRetValue* rv) {
151-
std::string file_name = this->GetPath(args[0]);
152-
file_name = BuildSharedLibrary(file_name);
153-
std::string bin;
143+
ffi::Function::SetGlobal("tvm.rpc.server.load_module",
144+
ffi::Function::FromUnpacked([this](const std::string& path) {
145+
std::string file_name = this->GetPath(path);
146+
file_name = BuildSharedLibrary(file_name);
147+
LOG(INFO) << "Load module from " << file_name << " ...";
148+
return Module::LoadFromFile(file_name, "");
149+
}));
154150

155-
std::ifstream fs(file_name, std::ios::in | std::ios::binary);
156-
ICHECK(!fs.fail()) << "Cannot open " << file_name;
157-
fs.seekg(0, std::ios::end);
158-
size_t size = static_cast<size_t>(fs.tellg());
159-
fs.seekg(0, std::ios::beg);
160-
bin.resize(size);
161-
fs.read(dmlc::BeginPtr(bin), size);
151+
ffi::Function::SetGlobal("tvm.rpc.server.download_linked_module",
152+
ffi::Function::FromUnpacked([this](const std::string& path) {
153+
std::string file_name = this->GetPath(path);
154+
file_name = BuildSharedLibrary(file_name);
155+
std::string bin;
162156

163-
TVMByteArray binarr;
164-
binarr.data = bin.data();
165-
binarr.size = bin.length();
166-
*rv = binarr;
167-
LOG(INFO) << "Send linked module " << file_name << " to client";
168-
});
157+
std::ifstream fs(file_name, std::ios::in | std::ios::binary);
158+
ICHECK(!fs.fail()) << "Cannot open " << file_name;
159+
fs.seekg(0, std::ios::end);
160+
size_t size = static_cast<size_t>(fs.tellg());
161+
fs.seekg(0, std::ios::beg);
162+
bin.resize(size);
163+
fs.read(dmlc::BeginPtr(bin), size);
164+
LOG(INFO) << "Send linked module " << file_name << " to client";
165+
return ffi::Bytes(bin);
166+
}));
169167
}
170168
/*!
171169
* \brief GetPath To get the work path from packed function

apps/cpp_rpc/rpc_server.cc

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -398,8 +398,6 @@ void RPCServerCreate(std::string host, int port, int port_end, std::string track
398398
rpc.Start();
399399
}
400400

401-
TVM_REGISTER_GLOBAL("rpc.ServerCreate").set_body([](TVMArgs args, TVMRetValue* rv) {
402-
RPCServerCreate(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7]);
403-
});
401+
TVM_REGISTER_GLOBAL("rpc.ServerCreate").set_body_typed(RPCServerCreate);
404402
} // namespace runtime
405403
} // namespace tvm

0 commit comments

Comments
 (0)