-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Arm backend: Add shared GPU runtime #22607
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
5c075ea
Arm backend: Add shared GPU runtime
wwwind d6221d2
Arm backend: Addressed comments.
wwwind 432da58
Merge branch 'main' into unified_gpu
wwwind a5a807a
Merge branch 'main' into unified_gpu
wwwind 61db1b4
Arm backend: Renamed to VulkanShared everything.
wwwind ece43f3
Arm backend: Updated README
wwwind 737f2af
Arm backend: Renamed leftovers.
wwwind f6309b9
Arm backend: One left rename.
wwwind File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| load( | ||
| "@fbcode_macros//build_defs:build_file_migration.bzl", | ||
| "fbcode_target", | ||
| "non_fbcode_target", | ||
| ) | ||
| load(":targets.bzl", "define_common_targets") | ||
|
|
||
| oncall("executorch") | ||
|
|
||
| non_fbcode_target(_kind = define_common_targets,) | ||
| fbcode_target(_kind = define_common_targets,) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,97 @@ | ||
| # Copyright 2026 Arm Limited and/or its affiliates. | ||
| # | ||
| # This source code is licensed under the BSD-style license found in the | ||
| # LICENSE file in the root directory of this source tree. | ||
|
|
||
| cmake_minimum_required(VERSION 3.19) | ||
|
|
||
| if(NOT EXECUTORCH_ROOT) | ||
| set(EXECUTORCH_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/../..) | ||
| endif() | ||
|
|
||
| include(GNUInstallDirs) | ||
| find_package(Threads REQUIRED) | ||
|
|
||
| set(VULKAN_SHARED_HEADERS_PATH | ||
| ${EXECUTORCH_ROOT}/backends/vulkan/third-party/Vulkan-Headers | ||
| ) | ||
|
|
||
| if(NOT EXISTS "${VULKAN_SHARED_HEADERS_PATH}/include/vulkan/vulkan.h") | ||
| message( | ||
| FATAL_ERROR | ||
| "The shared Vulkan runtime requires the vendored Vulkan-Headers submodule. " | ||
| "Run from the repository root:\n" | ||
| " git submodule update --init " | ||
| "backends/vulkan/third-party/Vulkan-Headers" | ||
| ) | ||
| endif() | ||
|
|
||
| # SHARED on purpose: VGF and Vulkan may be separate delegate DSOs, but they must | ||
| # observe one process-wide registry. A static copy in each DSO would create | ||
| # independent registries and defeat context sharing. | ||
| add_library( | ||
| executorch_vulkan_shared_runtime SHARED | ||
| ${CMAKE_CURRENT_SOURCE_DIR}/runtime/SharedVulkanContext.cpp | ||
| ${CMAKE_CURRENT_SOURCE_DIR}/runtime/SharedVulkanContextRegistry.cpp | ||
| ${CMAKE_CURRENT_SOURCE_DIR}/runtime/SharedVulkanRuntimeConfig.cpp | ||
| ) | ||
| add_library( | ||
| executorch::vulkan_shared_runtime ALIAS executorch_vulkan_shared_runtime | ||
| ) | ||
|
|
||
| target_compile_definitions( | ||
| executorch_vulkan_shared_runtime PRIVATE EXECUTORCH_VULKAN_SHARED_BUILDING | ||
| ) | ||
|
|
||
| target_include_directories( | ||
| executorch_vulkan_shared_runtime | ||
| PUBLIC $<BUILD_INTERFACE:${EXECUTORCH_ROOT}/..> | ||
| $<BUILD_INTERFACE:${EXECUTORCH_ROOT}/runtime/core/portable_type/c10> | ||
| $<BUILD_INTERFACE:${VULKAN_SHARED_HEADERS_PATH}/include> | ||
| $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}> | ||
| ) | ||
|
|
||
| target_link_libraries( | ||
| executorch_vulkan_shared_runtime | ||
| PUBLIC executorch_core | ||
| PRIVATE Threads::Threads | ||
| ) | ||
|
|
||
| set_target_properties( | ||
| executorch_vulkan_shared_runtime | ||
| PROPERTIES CXX_STANDARD 17 | ||
| CXX_STANDARD_REQUIRED YES | ||
| CXX_VISIBILITY_PRESET hidden | ||
| VISIBILITY_INLINES_HIDDEN YES | ||
| ) | ||
|
|
||
| install( | ||
| TARGETS executorch_vulkan_shared_runtime | ||
| EXPORT ExecuTorchTargets | ||
| ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} | ||
| LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} | ||
| RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} | ||
| INCLUDES | ||
| DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} | ||
| ) | ||
|
|
||
| install( | ||
| DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/runtime/ | ||
| DESTINATION | ||
| ${CMAKE_INSTALL_INCLUDEDIR}/executorch/backends/vulkan_shared/runtime | ||
| FILES_MATCHING | ||
| PATTERN "*.h" | ||
| PATTERN "test" EXCLUDE | ||
| ) | ||
|
|
||
| # SharedVulkanContext.h is a public installed header and includes | ||
| # <vulkan/vulkan.h>. Install the same vendored headers used by the build so an | ||
| # installed ExecuTorch package does not depend on an unrelated system Vulkan | ||
| # SDK. | ||
| install(DIRECTORY ${VULKAN_SHARED_HEADERS_PATH}/include/ | ||
| DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} | ||
| ) | ||
|
|
||
| if(EXECUTORCH_BUILD_TESTS) | ||
| add_subdirectory(runtime/test) | ||
| endif() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,64 @@ | ||
| # Shared Vulkan runtime | ||
|
|
||
| This component is not a standalone ExecuTorch backend. It does not | ||
| partition graphs, register a backend, or execute delegated operators. | ||
|
|
||
| This component is the backend-neutral runtime bridge used by the VGF and | ||
| ExecuTorch Vulkan delegates. It deliberately does not introduce a unified | ||
| partitioner or a wrapper delegate. | ||
|
|
||
| The standard AOT flow remains explicit partitioner composition, with VGF | ||
| claiming supported regions first and Vulkan filling the remaining regions: | ||
|
|
||
| ```python | ||
| lowered = to_edge_transform_and_lower( | ||
| exported, | ||
| partitioner=[ | ||
| VgfPartitioner(vgf_compile_spec), | ||
| VulkanPartitioner(vulkan_compile_spec), | ||
| ], | ||
| ) | ||
| ``` | ||
|
|
||
| ## Runtime options | ||
|
|
||
| Context selection is configured at model load time through `RuntimeSpec` / | ||
| `BackendOptions`, not through serialized `CompileSpec` values: | ||
|
|
||
| | Key | Type | Default | Accepted values | | ||
| | --- | --- | --- | --- | | ||
| | `vulkan_shared_context_name` | string | `default` | Any non-empty context_name | | ||
| | `vulkan_shared_context_mode` | string | `lookup_or_create` | `disabled`, `lookup_only`, `lookup_or_create`, `create_only` | | ||
| | `vulkan_shared_group_id` | int | `0` | Any `int` value | | ||
|
|
||
| Both delegates must receive the same option values to resolve the same registry | ||
| key. | ||
|
|
||
| ## Ownership and validation | ||
|
|
||
| `SharedVulkanContext` carries Vulkan handles but never calls Vulkan entry points | ||
| itself. Every registered context must provide a non-null `lifetime_anchor` whose | ||
| lifetime guarantees that the Vulkan instance, physical device, device, and queue | ||
| remain valid until the final `SharedVulkanContextPtr` is released. For a | ||
| backend-created context, the anchor can own the backend runtime and perform | ||
| teardown through that backend's Vulkan dispatch mechanism. For externally | ||
| created Vulkan objects, the application must provide an anchor whose ownership | ||
| keeps those objects alive for the same period. | ||
|
|
||
| `unregister_context()` removes the context from the registry and prevents new | ||
| lookups; it does not revoke `SharedVulkanContextPtr` instances already held by | ||
| delegates. Actual Vulkan teardown is therefore safe only after the final | ||
| outstanding context reference releases its `lifetime_anchor`. The registry | ||
| itself is intentionally process-lifetime; call `unregister_context()` to remove | ||
| registry discoverability before deterministic teardown. | ||
|
|
||
| The `VkQueue` is shared process state and Vulkan queue operations require | ||
| external host synchronization. Consumers must issue queue operations through | ||
| `SharedVulkanContext::with_locked_queue()` so independently initialized delegates | ||
| serialize access using the mutex stored in the shared context rather than | ||
| backend-local locks. | ||
|
|
||
| The registrant also declares the device extensions enabled at `VkDevice` | ||
| creation. A consuming backend must check its required extensions with | ||
| `has_device_extension()` before using the context; Vulkan does not expose a | ||
| post-creation query for the list of extensions that were enabled. | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,64 @@ | ||
| /* | ||
| * Copyright 2026 Arm Limited and/or its affiliates. | ||
| * | ||
| * This source code is licensed under the BSD-style license found in the | ||
| * LICENSE file in the root directory of this source tree. | ||
| */ | ||
|
|
||
| #include <executorch/backends/vulkan_shared/runtime/SharedVulkanContext.h> | ||
|
|
||
| #include <algorithm> | ||
| #include <utility> | ||
|
|
||
| namespace executorch { | ||
| namespace backends { | ||
| namespace vulkan_shared { | ||
|
|
||
| SharedVulkanContext::SharedVulkanContext( | ||
| SharedVulkanContextCreateInfo create_info) | ||
| : create_info_(std::move(create_info)) {} | ||
|
|
||
| SharedVulkanContext::~SharedVulkanContext() = default; | ||
|
|
||
| const SharedVulkanContextKey& SharedVulkanContext::key() const { | ||
| return create_info_.key; | ||
| } | ||
|
|
||
| VkInstance SharedVulkanContext::instance() const { | ||
| return create_info_.instance; | ||
| } | ||
|
|
||
| VkPhysicalDevice SharedVulkanContext::physical_device() const { | ||
| return create_info_.physical_device; | ||
| } | ||
|
|
||
| VkDevice SharedVulkanContext::device() const { | ||
| return create_info_.device; | ||
| } | ||
|
|
||
| uint32_t SharedVulkanContext::queue_family_index() const { | ||
| return create_info_.queue_family_index; | ||
| } | ||
|
|
||
| bool SharedVulkanContext::has_device_extension( | ||
| std::string_view extension_name) const { | ||
| return std::any_of( | ||
| create_info_.enabled_device_extensions.begin(), | ||
| create_info_.enabled_device_extensions.end(), | ||
| [extension_name](const std::string& enabled_extension) { | ||
| return enabled_extension == extension_name; | ||
| }); | ||
| } | ||
|
|
||
| bool SharedVulkanContext::is_valid() const { | ||
| return create_info_.key.valid() && create_info_.instance != VK_NULL_HANDLE && | ||
| create_info_.physical_device != VK_NULL_HANDLE && | ||
| create_info_.device != VK_NULL_HANDLE && | ||
| create_info_.queue != VK_NULL_HANDLE && | ||
| create_info_.queue_family_index != std::numeric_limits<uint32_t>::max() && | ||
| create_info_.lifetime_anchor != nullptr; | ||
| } | ||
|
|
||
| } // namespace vulkan_shared | ||
| } // namespace backends | ||
| } // namespace executorch |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,100 @@ | ||
| /* | ||
| * Copyright 2026 Arm Limited and/or its affiliates. | ||
| * | ||
| * This source code is licensed under the BSD-style license found in the | ||
| * LICENSE file in the root directory of this source tree. | ||
| */ | ||
|
|
||
| #pragma once | ||
|
|
||
| #include <executorch/backends/vulkan_shared/runtime/export.h> | ||
|
|
||
| #include <vulkan/vulkan.h> | ||
|
|
||
| #include <cstdint> | ||
| #include <limits> | ||
| #include <memory> | ||
| #include <mutex> | ||
| #include <string> | ||
| #include <string_view> | ||
| #include <utility> | ||
| #include <vector> | ||
|
|
||
| namespace executorch { | ||
| namespace backends { | ||
| namespace vulkan_shared { | ||
|
|
||
| struct SharedVulkanContextKey final { | ||
| std::string context_name; | ||
| int group_id = 0; | ||
|
|
||
| bool valid() const { | ||
| return !context_name.empty(); | ||
| } | ||
|
|
||
| friend bool operator==( | ||
| const SharedVulkanContextKey& lhs, | ||
| const SharedVulkanContextKey& rhs) { | ||
| return lhs.group_id == rhs.group_id && lhs.context_name == rhs.context_name; | ||
| } | ||
|
|
||
| friend bool operator!=( | ||
| const SharedVulkanContextKey& lhs, | ||
| const SharedVulkanContextKey& rhs) { | ||
| return !(lhs == rhs); | ||
| } | ||
| }; | ||
|
|
||
| // The shared layer carries Vulkan handles but deliberately does not call Vulkan | ||
| // entry points itself. Every registered context must provide a lifetime_anchor | ||
| // whose lifetime guarantees that instance, physical_device, device, and queue | ||
| // remain valid until the final SharedVulkanContext reference is released. The | ||
| // anchor destructor may perform backend/application Vulkan teardown. | ||
| struct SharedVulkanContextCreateInfo final { | ||
| SharedVulkanContextKey key; | ||
| VkInstance instance = VK_NULL_HANDLE; | ||
| VkPhysicalDevice physical_device = VK_NULL_HANDLE; | ||
| VkDevice device = VK_NULL_HANDLE; | ||
| VkQueue queue = VK_NULL_HANDLE; | ||
| uint32_t queue_family_index = std::numeric_limits<uint32_t>::max(); | ||
| std::vector<std::string> enabled_device_extensions; | ||
| std::shared_ptr<void> lifetime_anchor; | ||
| }; | ||
|
|
||
| class EXECUTORCH_VULKAN_SHARED_API SharedVulkanContext final { | ||
| public: | ||
| explicit SharedVulkanContext(SharedVulkanContextCreateInfo create_info); | ||
| ~SharedVulkanContext(); | ||
|
|
||
| SharedVulkanContext(const SharedVulkanContext&) = delete; | ||
| SharedVulkanContext& operator=(const SharedVulkanContext&) = delete; | ||
|
|
||
| const SharedVulkanContextKey& key() const; | ||
| VkInstance instance() const; | ||
| VkPhysicalDevice physical_device() const; | ||
| VkDevice device() const; | ||
|
|
||
| // Vulkan queue operations require external host synchronization. All | ||
| // delegates sharing this context must issue queue operations through this | ||
| // callback so they synchronize on the same mutex. The VkQueue must not be | ||
| // retained and used after the callback returns. | ||
| template <typename Fn> | ||
| decltype(auto) with_locked_queue(Fn&& fn) const { | ||
| std::lock_guard<std::mutex> lock(queue_mutex_); | ||
| return std::forward<Fn>(fn)(create_info_.queue); | ||
| } | ||
|
|
||
| uint32_t queue_family_index() const; | ||
| bool has_device_extension(std::string_view extension_name) const; | ||
| bool is_valid() const; | ||
|
|
||
| private: | ||
| SharedVulkanContextCreateInfo create_info_; | ||
| mutable std::mutex queue_mutex_; | ||
| }; | ||
|
|
||
| using SharedVulkanContextPtr = std::shared_ptr<SharedVulkanContext>; | ||
|
|
||
| } // namespace vulkan_shared | ||
| } // namespace backends | ||
| } // namespace executorch |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.