Skip to content
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

[move-stdlib] Use vector::move_range inside vector, and evaluate performance / calibrate gas #14862

Merged
merged 8 commits into from
Dec 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions aptos-move/e2e-benchmark/data/calibration_values.tsv
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,12 @@ FungibleAssetMint 60 0.930 1.098 235.8
IncGlobalMilestoneAggV2 { milestone_every: 1 } 60 0.914 1.051 33.5
IncGlobalMilestoneAggV2 { milestone_every: 2 } 60 0.914 1.105 19.0
EmitEvents { count: 1000 } 60 0.937 1.158 8818.7
VectorTrimAppend { vec_len: 3000, element_len: 1, index: 0, repeats: 0 } 6 0.925 1.001 6058.1
VectorTrimAppend { vec_len: 3000, element_len: 1, index: 100, repeats: 1000 } 6 0.925 1.001 34000.0
VectorTrimAppend { vec_len: 3000, element_len: 1, index: 2990, repeats: 1000 } 6 0.925 1.001 17626.5
VectorRemoveInsert { vec_len: 3000, element_len: 1, index: 100, repeats: 1000 } 6 0.925 1.001 30870.3
VectorRemoveInsert { vec_len: 3000, element_len: 1, index: 2998, repeats: 1000 } 6 0.925 1.001 20343.2
VectorRangeMove { vec_len: 3000, element_len: 1, index: 1000, move_len: 500, repeats: 1000 } 6 0.925 1.001 65311
VectorTrimAppend { vec_len: 100, element_len: 100, index: 0, repeats: 0 } 6 0.925 1.001 277.0
VectorTrimAppend { vec_len: 100, element_len: 100, index: 10, repeats: 1000 } 6 0.925 1.001 12146.6
VectorRangeMove { vec_len: 100, element_len: 100, index: 50, move_len: 10, repeats: 1000 } 6 0.925 1.001 7098
60 changes: 60 additions & 0 deletions aptos-move/e2e-benchmark/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,66 @@ fn main() {
EntryPoints::IncGlobalMilestoneAggV2 { milestone_every: 1 },
EntryPoints::IncGlobalMilestoneAggV2 { milestone_every: 2 },
EntryPoints::EmitEvents { count: 1000 },
// long vectors with small elements
EntryPoints::VectorTrimAppend {
// baseline, only vector creation
vec_len: 3000,
element_len: 1,
index: 0,
repeats: 0,
},
EntryPoints::VectorTrimAppend {
vec_len: 3000,
element_len: 1,
index: 100,
repeats: 1000,
},
EntryPoints::VectorTrimAppend {
vec_len: 3000,
element_len: 1,
index: 2990,
repeats: 1000,
},
EntryPoints::VectorRemoveInsert {
vec_len: 3000,
element_len: 1,
index: 100,
repeats: 1000,
},
EntryPoints::VectorRemoveInsert {
vec_len: 3000,
element_len: 1,
index: 2998,
repeats: 1000,
},
// EntryPoints::VectorRangeMove {
// vec_len: 3000,
// element_len: 1,
// index: 1000,
// move_len: 500,
// repeats: 1000,
// },
// vectors with large elements
EntryPoints::VectorTrimAppend {
// baseline, only vector creation
vec_len: 100,
element_len: 100,
index: 0,
repeats: 0,
},
EntryPoints::VectorTrimAppend {
vec_len: 100,
element_len: 100,
index: 10,
repeats: 1000,
},
// EntryPoints::VectorRangeMove {
// vec_len: 100,
// element_len: 100,
// index: 50,
// move_len: 10,
// repeats: 1000,
// },
];

let mut failures = Vec::new();
Expand Down
57 changes: 57 additions & 0 deletions aptos-move/framework/move-stdlib/doc/features.md
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,8 @@ return true.
- [Function `transaction_simulation_enhancement_enabled`](#0x1_features_transaction_simulation_enhancement_enabled)
- [Function `get_collection_owner_feature`](#0x1_features_get_collection_owner_feature)
- [Function `is_collection_owner_enabled`](#0x1_features_is_collection_owner_enabled)
- [Function `get_native_memory_operations_feature`](#0x1_features_get_native_memory_operations_feature)
- [Function `is_native_memory_operations_enabled`](#0x1_features_is_native_memory_operations_enabled)
- [Function `change_feature_flags`](#0x1_features_change_feature_flags)
- [Function `change_feature_flags_internal`](#0x1_features_change_feature_flags_internal)
- [Function `change_feature_flags_for_next_epoch`](#0x1_features_change_feature_flags_for_next_epoch)
Expand Down Expand Up @@ -671,6 +673,15 @@ Lifetime: transient



<a id="0x1_features_NATIVE_MEMORY_OPERATIONS"></a>



<pre><code><b>const</b> <a href="features.md#0x1_features_NATIVE_MEMORY_OPERATIONS">NATIVE_MEMORY_OPERATIONS</a>: u64 = 80;
</code></pre>



<a id="0x1_features_NEW_ACCOUNTS_DEFAULT_TO_FA_APT_STORE"></a>

Lifetime: transient
Expand Down Expand Up @@ -3274,6 +3285,52 @@ Deprecated feature



</details>

<a id="0x1_features_get_native_memory_operations_feature"></a>

## Function `get_native_memory_operations_feature`



<pre><code><b>public</b> <b>fun</b> <a href="features.md#0x1_features_get_native_memory_operations_feature">get_native_memory_operations_feature</a>(): u64
</code></pre>



<details>
<summary>Implementation</summary>


<pre><code><b>public</b> <b>fun</b> <a href="features.md#0x1_features_get_native_memory_operations_feature">get_native_memory_operations_feature</a>(): u64 { <a href="features.md#0x1_features_NATIVE_MEMORY_OPERATIONS">NATIVE_MEMORY_OPERATIONS</a> }
</code></pre>



</details>

<a id="0x1_features_is_native_memory_operations_enabled"></a>

## Function `is_native_memory_operations_enabled`



<pre><code><b>public</b> <b>fun</b> <a href="features.md#0x1_features_is_native_memory_operations_enabled">is_native_memory_operations_enabled</a>(): bool
</code></pre>



<details>
<summary>Implementation</summary>


<pre><code><b>public</b> <b>fun</b> <a href="features.md#0x1_features_is_native_memory_operations_enabled">is_native_memory_operations_enabled</a>(): bool <b>acquires</b> <a href="features.md#0x1_features_Features">Features</a> {
<a href="features.md#0x1_features_is_enabled">is_enabled</a>(<a href="features.md#0x1_features_NATIVE_MEMORY_OPERATIONS">NATIVE_MEMORY_OPERATIONS</a>)
}
</code></pre>



</details>

<a id="0x1_features_change_feature_flags"></a>
Expand Down
131 changes: 118 additions & 13 deletions aptos-move/framework/move-stdlib/doc/vector.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ the return on investment didn't seem worth it for these simple functions.
- [Function `remove`](#0x1_vector_remove)
- [Function `remove_value`](#0x1_vector_remove_value)
- [Function `swap_remove`](#0x1_vector_swap_remove)
- [Function `replace`](#0x1_vector_replace)
- [Function `for_each`](#0x1_vector_for_each)
- [Function `for_each_reverse`](#0x1_vector_for_each_reverse)
- [Function `for_each_ref`](#0x1_vector_for_each_ref)
Expand Down Expand Up @@ -146,6 +147,18 @@ The length of the vectors are not equal.



<a id="0x1_vector_USE_MOVE_RANGE"></a>

Whether to utilize native vector::move_range
Vector module cannot call features module, due to cyclic dependency,
so this is a constant.


<pre><code><b>const</b> <a href="vector.md#0x1_vector_USE_MOVE_RANGE">USE_MOVE_RANGE</a>: bool = <b>true</b>;
</code></pre>



<a id="0x1_vector_empty"></a>

## Function `empty`
Expand Down Expand Up @@ -482,8 +495,15 @@ Pushes all of the elements of the <code>other</code> vector into the <code>self<


<pre><code><b>public</b> <b>fun</b> <a href="vector.md#0x1_vector_append">append</a>&lt;Element&gt;(self: &<b>mut</b> <a href="vector.md#0x1_vector">vector</a>&lt;Element&gt;, other: <a href="vector.md#0x1_vector">vector</a>&lt;Element&gt;) {
<a href="vector.md#0x1_vector_reverse">reverse</a>(&<b>mut</b> other);
<a href="vector.md#0x1_vector_reverse_append">reverse_append</a>(self, other);
<b>if</b> (<a href="vector.md#0x1_vector_USE_MOVE_RANGE">USE_MOVE_RANGE</a>) {
<b>let</b> self_length = <a href="vector.md#0x1_vector_length">length</a>(self);
<b>let</b> other_length = <a href="vector.md#0x1_vector_length">length</a>(&other);
<a href="vector.md#0x1_vector_move_range">move_range</a>(&<b>mut</b> other, 0, other_length, self, self_length);
<a href="vector.md#0x1_vector_destroy_empty">destroy_empty</a>(other);
} <b>else</b> {
<a href="vector.md#0x1_vector_reverse">reverse</a>(&<b>mut</b> other);
<a href="vector.md#0x1_vector_reverse_append">reverse_append</a>(self, other);
}
}
</code></pre>

Expand Down Expand Up @@ -525,7 +545,11 @@ Pushes all of the elements of the <code>other</code> vector into the <code>self<

## Function `trim`

Trim a vector to a smaller size, returning the evicted elements in order
Splits (trims) the collection into two at the given index.
Returns a newly allocated vector containing the elements in the range [new_len, len).
After the call, the original vector will be left containing the elements [0, new_len)
with its previous capacity unchanged.
In many languages this is also called <code>split_off</code>.


<pre><code><b>public</b> <b>fun</b> <a href="vector.md#0x1_vector_trim">trim</a>&lt;Element&gt;(self: &<b>mut</b> <a href="vector.md#0x1_vector">vector</a>&lt;Element&gt;, new_len: u64): <a href="vector.md#0x1_vector">vector</a>&lt;Element&gt;
Expand All @@ -538,9 +562,21 @@ Trim a vector to a smaller size, returning the evicted elements in order


<pre><code><b>public</b> <b>fun</b> <a href="vector.md#0x1_vector_trim">trim</a>&lt;Element&gt;(self: &<b>mut</b> <a href="vector.md#0x1_vector">vector</a>&lt;Element&gt;, new_len: u64): <a href="vector.md#0x1_vector">vector</a>&lt;Element&gt; {
<b>let</b> res = <a href="vector.md#0x1_vector_trim_reverse">trim_reverse</a>(self, new_len);
<a href="vector.md#0x1_vector_reverse">reverse</a>(&<b>mut</b> res);
res
<b>let</b> len = <a href="vector.md#0x1_vector_length">length</a>(self);
<b>assert</b>!(new_len &lt;= len, <a href="vector.md#0x1_vector_EINDEX_OUT_OF_BOUNDS">EINDEX_OUT_OF_BOUNDS</a>);

<b>let</b> other = <a href="vector.md#0x1_vector_empty">empty</a>();
<b>if</b> (<a href="vector.md#0x1_vector_USE_MOVE_RANGE">USE_MOVE_RANGE</a>) {
<a href="vector.md#0x1_vector_move_range">move_range</a>(self, new_len, len - new_len, &<b>mut</b> other, 0);
} <b>else</b> {
<b>while</b> (len &gt; new_len) {
<a href="vector.md#0x1_vector_push_back">push_back</a>(&<b>mut</b> other, <a href="vector.md#0x1_vector_pop_back">pop_back</a>(self));
len = len - 1;
};
<a href="vector.md#0x1_vector_reverse">reverse</a>(&<b>mut</b> other);
};

other
}
</code></pre>

Expand Down Expand Up @@ -728,10 +764,27 @@ Aborts if out of bounds.
<pre><code><b>public</b> <b>fun</b> <a href="vector.md#0x1_vector_insert">insert</a>&lt;Element&gt;(self: &<b>mut</b> <a href="vector.md#0x1_vector">vector</a>&lt;Element&gt;, i: u64, e: Element) {
<b>let</b> len = <a href="vector.md#0x1_vector_length">length</a>(self);
<b>assert</b>!(i &lt;= len, <a href="vector.md#0x1_vector_EINDEX_OUT_OF_BOUNDS">EINDEX_OUT_OF_BOUNDS</a>);
<a href="vector.md#0x1_vector_push_back">push_back</a>(self, e);
<b>while</b> (i &lt; len) {
<a href="vector.md#0x1_vector_swap">swap</a>(self, i, len);
i = i + 1;

<b>if</b> (<a href="vector.md#0x1_vector_USE_MOVE_RANGE">USE_MOVE_RANGE</a>) {
<b>if</b> (i + 2 &gt;= len) {
// When we are close <b>to</b> the end, it is cheaper <b>to</b> not create
// a temporary <a href="vector.md#0x1_vector">vector</a>, and swap directly
<a href="vector.md#0x1_vector_push_back">push_back</a>(self, e);
<b>while</b> (i &lt; len) {
<a href="vector.md#0x1_vector_swap">swap</a>(self, i, len);
i = i + 1;
};
} <b>else</b> {
<b>let</b> other = <a href="vector.md#0x1_vector_singleton">singleton</a>(e);
<a href="vector.md#0x1_vector_move_range">move_range</a>(&<b>mut</b> other, 0, 1, self, i);
<a href="vector.md#0x1_vector_destroy_empty">destroy_empty</a>(other);
}
} <b>else</b> {
<a href="vector.md#0x1_vector_push_back">push_back</a>(self, e);
<b>while</b> (i &lt; len) {
<a href="vector.md#0x1_vector_swap">swap</a>(self, i, len);
i = i + 1;
};
};
}
</code></pre>
Expand Down Expand Up @@ -763,9 +816,25 @@ Aborts if <code>i</code> is out of bounds.
// i out of bounds; <b>abort</b>
<b>if</b> (i &gt;= len) <b>abort</b> <a href="vector.md#0x1_vector_EINDEX_OUT_OF_BOUNDS">EINDEX_OUT_OF_BOUNDS</a>;

len = len - 1;
<b>while</b> (i &lt; len) <a href="vector.md#0x1_vector_swap">swap</a>(self, i, { i = i + 1; i });
<a href="vector.md#0x1_vector_pop_back">pop_back</a>(self)
<b>if</b> (<a href="vector.md#0x1_vector_USE_MOVE_RANGE">USE_MOVE_RANGE</a>) {
// When we are close <b>to</b> the end, it is cheaper <b>to</b> not create
// a temporary <a href="vector.md#0x1_vector">vector</a>, and swap directly
<b>if</b> (i + 3 &gt;= len) {
len = len - 1;
<b>while</b> (i &lt; len) <a href="vector.md#0x1_vector_swap">swap</a>(self, i, { i = i + 1; i });
<a href="vector.md#0x1_vector_pop_back">pop_back</a>(self)
} <b>else</b> {
<b>let</b> other = <a href="vector.md#0x1_vector_empty">empty</a>();
<a href="vector.md#0x1_vector_move_range">move_range</a>(self, i, 1, &<b>mut</b> other, 0);
<b>let</b> result = <a href="vector.md#0x1_vector_pop_back">pop_back</a>(&<b>mut</b> other);
<a href="vector.md#0x1_vector_destroy_empty">destroy_empty</a>(other);
result
}
} <b>else</b> {
len = len - 1;
<b>while</b> (i &lt; len) <a href="vector.md#0x1_vector_swap">swap</a>(self, i, { i = i + 1; i });
<a href="vector.md#0x1_vector_pop_back">pop_back</a>(self)
}
}
</code></pre>

Expand Down Expand Up @@ -838,6 +907,42 @@ Aborts if <code>i</code> is out of bounds.



</details>

<a id="0x1_vector_replace"></a>

## Function `replace`

Replace the <code>i</code>th element of the vector <code>self</code> with the given value, and return
to the caller the value that was there before.
Aborts if <code>i</code> is out of bounds.


<pre><code><b>public</b> <b>fun</b> <a href="vector.md#0x1_vector_replace">replace</a>&lt;Element&gt;(self: &<b>mut</b> <a href="vector.md#0x1_vector">vector</a>&lt;Element&gt;, i: u64, val: Element): Element
</code></pre>



<details>
<summary>Implementation</summary>


<pre><code><b>public</b> <b>fun</b> <a href="vector.md#0x1_vector_replace">replace</a>&lt;Element&gt;(self: &<b>mut</b> <a href="vector.md#0x1_vector">vector</a>&lt;Element&gt;, i: u64, val: Element): Element {
<b>let</b> last_idx = <a href="vector.md#0x1_vector_length">length</a>(self);
<b>assert</b>!(i &lt; last_idx, <a href="vector.md#0x1_vector_EINDEX_OUT_OF_BOUNDS">EINDEX_OUT_OF_BOUNDS</a>);
// TODO: Enable after tests are fixed.
// <b>if</b> (<a href="vector.md#0x1_vector_USE_MOVE_RANGE">USE_MOVE_RANGE</a>) {
// <a href="mem.md#0x1_mem_replace">mem::replace</a>(<a href="vector.md#0x1_vector_borrow_mut">borrow_mut</a>(self, i), val)
// } <b>else</b> {
<a href="vector.md#0x1_vector_push_back">push_back</a>(self, val);
<a href="vector.md#0x1_vector_swap">swap</a>(self, i, last_idx);
<a href="vector.md#0x1_vector_pop_back">pop_back</a>(self)
// }
}
</code></pre>



</details>

<a id="0x1_vector_for_each"></a>
Expand Down
Loading
Loading