Skip to content

Commit fc2f5d5

Browse files
authored
Merge branch 'main' into toupstream/bin_node
2 parents aa0055f + 1621fa2 commit fc2f5d5

105 files changed

Lines changed: 2920 additions & 562 deletions

File tree

Some content is hidden

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

.github/workflows/mlx.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,11 @@ jobs:
6666
echo "::endgroup::"
6767
6868
echo "::group::Build test runners"
69-
${CONDA_RUN} cmake --build cmake-out --target op_test_runner multi_thread_test_runner -j$(( $(sysctl -n hw.ncpu) - 1 ))
69+
${CONDA_RUN} cmake --build cmake-out --target op_test_runner multi_thread_test_runner mlx_mutable_state_test -j$(( $(sysctl -n hw.ncpu) - 1 ))
70+
echo "::endgroup::"
71+
72+
echo "::group::Run mutable-state (multi-session) unit test"
73+
./cmake-out/backends/mlx/test/mlx_mutable_state_test
7074
echo "::endgroup::"
7175
7276
echo "::group::Run op unit tests"

backends/arm/operators/op_tosa_identity.py

Lines changed: 12 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -3,42 +3,28 @@
33
# This source code is licensed under the BSD-style license found in the
44
# LICENSE file in the root directory of this source tree.
55

6-
from typing import Any, List
7-
8-
import torch
96
import tosa_serializer as ts
107

11-
from executorch.backends.arm.operators.node_visitor import (
12-
NodeVisitor,
13-
register_node_visitor,
14-
)
15-
from executorch.backends.arm.operators.operator_validation_utils import (
16-
validate_num_inputs,
17-
validate_same_dtype,
18-
validate_valid_dtype,
8+
from executorch.backends.arm.operators.node_visitor import register_node_visitor
9+
from executorch.backends.arm.operators.simple_node_visitor import (
10+
SimpleNodeVisitor,
11+
SimpleNodeVisitorConfig,
1912
)
20-
from executorch.backends.arm.tosa.mapping import TosaArg
2113

2214

2315
@register_node_visitor
24-
class IdentityVisitor(NodeVisitor):
16+
class IdentityVisitor(SimpleNodeVisitor):
2517
"""Lower the TOSA IDENTITY op."""
2618

2719
target = "tosa.IDENTITY.default"
2820

29-
def define_node(
30-
self,
31-
node: torch.fx.Node,
32-
tosa_graph: Any,
33-
inputs: List[TosaArg],
34-
output: TosaArg,
35-
) -> None:
36-
validate_num_inputs(self.target, inputs, 1)
37-
validate_same_dtype(self.target, [inputs[0], output], ts)
38-
validate_valid_dtype(
39-
self.target,
40-
[inputs[0], output],
41-
[
21+
@classmethod
22+
def get_config(cls) -> SimpleNodeVisitorConfig:
23+
return SimpleNodeVisitorConfig(
24+
tosa_op=ts.Op.IDENTITY,
25+
attr_method="IdentityAttribute",
26+
num_inputs=1,
27+
input_dtypes=[
4228
ts.DType.BOOL,
4329
ts.DType.INT8,
4430
ts.DType.INT16,
@@ -49,16 +35,4 @@ def define_node(
4935
ts.DType.FP8E4M3,
5036
ts.DType.FP8E5M2,
5137
],
52-
self.tosa_spec,
53-
)
54-
55-
attr = ts.TosaSerializerAttribute()
56-
attr.IdentityAttribute()
57-
self._serialize_operator(
58-
node,
59-
tosa_graph,
60-
ts.Op.IDENTITY,
61-
[inputs[0].name],
62-
[output.name],
63-
attr,
6438
)

backends/arm/quantizer/quantization_annotator.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -631,6 +631,16 @@ def _get_fixed_qparams_qspec(
631631
if _transpose_dimname is not None:
632632
_one_to_one_shared_input_qspec.add(_transpose_dimname)
633633

634+
for _op in (
635+
getattr(torch.ops.aten.moveaxis, "int", None),
636+
getattr(torch.ops.aten.moveaxis, "intlist", None),
637+
getattr(torch.ops.aten.movedim, "int", None),
638+
getattr(torch.ops.aten.movedim, "intlist", None),
639+
):
640+
if _op is not None:
641+
_one_to_one_shared_input_qspec.add(_op)
642+
643+
634644
_one_to_one_shared_input_or_input_act_qspec: set[OpOverload] = {
635645
torch.ops.aten.alias.default,
636646
torch.ops.aten.clone.default,

backends/arm/runtime/VGFSetup.cpp

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -778,6 +778,73 @@ static bool find_memory_index(
778778
memory_type_out);
779779
}
780780

781+
bool VgfRepr::map_persistent_io_memory() {
782+
unmap_persistent_io_memory();
783+
784+
for (auto& io : IOs) {
785+
if (io.memory == VK_NULL_HANDLE) {
786+
ET_LOG(Error, "Cannot persistently map null Vulkan IO memory");
787+
unmap_persistent_io_memory();
788+
return false;
789+
}
790+
791+
void* persistent_memory = nullptr;
792+
793+
// IO resources may alias the same VkDeviceMemory. Vulkan memory must not be
794+
// mapped more than once at the same time, so map each unique memory once
795+
// and share the returned pointer across aliased IO entries.
796+
// Make sure that memory is HOST_VISIBLE and HOST_COHERENT.
797+
bool found_existing_mapping = false;
798+
auto mapped_memory_it = std::find_if(
799+
persistent_mapped_memories.begin(),
800+
persistent_mapped_memories.end(),
801+
[&](const auto& mapped_memory) {
802+
return mapped_memory.memory == io.memory;
803+
});
804+
805+
if (mapped_memory_it != persistent_mapped_memories.end()) {
806+
persistent_memory = mapped_memory_it->data;
807+
found_existing_mapping = true;
808+
}
809+
810+
if (!found_existing_mapping) {
811+
VkResult result = vkMapMemory(
812+
vk_device, io.memory, 0, VK_WHOLE_SIZE, 0, &persistent_memory);
813+
if (result != VK_SUCCESS) {
814+
ET_LOG(
815+
Error,
816+
"Failed to persistently map Vulkan IO memory, error %d",
817+
result);
818+
unmap_persistent_io_memory();
819+
return false;
820+
}
821+
822+
persistent_mapped_memories.push_back(PersistentMappedMemory{
823+
.memory = io.memory,
824+
.data = persistent_memory,
825+
});
826+
}
827+
828+
io.persistent_memory = persistent_memory;
829+
}
830+
831+
return true;
832+
}
833+
834+
void VgfRepr::unmap_persistent_io_memory() {
835+
for (const auto& mapped_memory : persistent_mapped_memories) {
836+
if (mapped_memory.memory != VK_NULL_HANDLE &&
837+
mapped_memory.data != nullptr) {
838+
vkUnmapMemory(vk_device, mapped_memory.memory);
839+
}
840+
}
841+
persistent_mapped_memories.clear();
842+
843+
for (auto& io : IOs) {
844+
io.persistent_memory = nullptr;
845+
}
846+
}
847+
781848
VkResult allocate_memory(
782849
VkPhysicalDevice physical,
783850
VkDevice device,
@@ -1839,6 +1906,7 @@ bool VgfRepr::process_vgf(
18391906
VK_NULL_HANDLE,
18401907
tensor_memory,
18411908
{0, 0, 0},
1909+
nullptr,
18421910
owns_memory,
18431911
true,
18441912
is_in});
@@ -1931,6 +1999,7 @@ bool VgfRepr::process_vgf(
19311999
VK_NULL_HANDLE,
19322000
buffer_memory,
19332001
{0, 0, 0},
2002+
nullptr,
19342003
owns_memory,
19352004
true,
19362005
is_in});
@@ -2117,6 +2186,7 @@ bool VgfRepr::process_vgf(
21172186
image_memory,
21182187
staging_memory,
21192188
image_extent,
2189+
nullptr,
21202190
true,
21212191
owns_image_memory,
21222192
is_in});
@@ -3433,6 +3503,15 @@ bool VgfRepr::process_vgf(
34333503
vkEndCommandBuffer(vk_execute_cmd);
34343504
}
34353505

3506+
{
3507+
VGF_PROFILE_SCOPE(event_tracer, "VGF_INIT_MAP_IO_MEMORY");
3508+
3509+
if (!map_persistent_io_memory()) {
3510+
ET_LOG(Error, "Failed to persistently map VGF IO memory");
3511+
return false;
3512+
}
3513+
}
3514+
34363515
return true;
34373516
}
34383517

@@ -3493,6 +3572,8 @@ bool VgfRepr::execute_vgf(executorch::runtime::EventTracer* event_tracer) {
34933572
}
34943573

34953574
void VgfRepr::free_vgf() {
3575+
unmap_persistent_io_memory();
3576+
34963577
if (vk_timestamp_query_pool != VK_NULL_HANDLE) {
34973578
vkDestroyQueryPool(vk_device, vk_timestamp_query_pool, nullptr);
34983579
vk_timestamp_query_pool = VK_NULL_HANDLE;

backends/arm/runtime/VGFSetup.h

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,17 @@ typedef struct IO {
4545
VkDeviceMemory image_memory;
4646
VkDeviceMemory memory;
4747
VkExtent3D image_extent;
48+
void* persistent_memory = nullptr;
4849
bool owns_memory = true;
4950
bool owns_image_memory = true;
5051
bool is_input;
5152
} IO;
5253

54+
typedef struct PersistentMappedMemory {
55+
VkDeviceMemory memory = VK_NULL_HANDLE;
56+
void* data = nullptr;
57+
} PersistentMappedMemory;
58+
5359
typedef struct SegmentState {
5460
int segment_id = -1;
5561
bool use_data_graph_pipeline = true;
@@ -128,18 +134,19 @@ class VgfRepr {
128134
std::vector<SegmentState> segments;
129135
std::vector<ResourceAlloc> extra_allocs;
130136

131-
bool map_io(IO* io, void** handle) {
132-
VkResult result =
133-
vkMapMemory(vk_device, io->memory, 0, VK_WHOLE_SIZE, 0, handle);
134-
if (result != VK_SUCCESS) {
135-
ET_LOG(Error, "Failed to map Vulkan IO memory");
137+
// Mapping to persistent IO memory
138+
static bool map_io(IO* io, void** handle) {
139+
if (io->persistent_memory == nullptr) {
140+
ET_LOG(Error, "Vulkan IO memory is not persistently mapped");
136141
return false;
137142
}
143+
*handle = io->persistent_memory;
138144
return true;
139145
}
140146

141-
void unmap_io(IO* io) {
142-
vkUnmapMemory(vk_device, io->memory);
147+
// Unmapping to persistent IO memory
148+
static void unmap_io(IO* io) {
149+
(void)io;
143150
}
144151

145152
~VgfRepr() {
@@ -168,6 +175,10 @@ class VgfRepr {
168175

169176
bool init_timestamp_queries();
170177
void read_timestamp_queries(executorch::runtime::EventTracer* event_tracer);
178+
179+
std::vector<PersistentMappedMemory> persistent_mapped_memories;
180+
bool map_persistent_io_memory();
181+
void unmap_persistent_io_memory();
171182
};
172183

173184
} // namespace vgf

0 commit comments

Comments
 (0)