Skip to content

Commit 9c6c2f2

Browse files
profiling upgrades (dfinity#91)
* upgrade for basic_dao * nft * rerun CI * collection motoko * rust collections * fix * fix * add utils * use utils in collections * refactor * fix * certified_map upgrade * readme * fix nft did * fix
1 parent 5158daf commit 9c6c2f2

File tree

48 files changed

+486
-241
lines changed

Some content is hidden

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

48 files changed

+486
-241
lines changed

.github/workflows/perf.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@ jobs:
1212
fail-fast: false
1313
env:
1414
DFX_VERSION: 0.15.0
15-
IC_REPL_VERSION: 0.4.3
15+
IC_REPL_VERSION: 0.5.0
1616
MOC_VERSION: 0.10.0
17-
IC_WASM_VERSION: 0.5.0
17+
IC_WASM_VERSION: 0.5.1
1818
steps:
1919
- uses: actions/checkout@v3
2020
- name: Checkout out gh-pages report

Cargo.lock

Lines changed: 25 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
[workspace]
22
members = [
3+
"utils/rust",
34
"collections/rust/src/hashmap",
45
"collections/rust/src/btreemap",
56
"collections/rust/src/heap",
@@ -24,5 +25,6 @@ opt-level = 2
2425
[workspace.dependencies]
2526
ic-cdk = "0.10.0"
2627
ic-cdk-timers = "0.4.0"
27-
candid = "0.9"
28+
candid = "0.9.8"
2829
serde = "1"
30+
ic-stable-structures = "0.5"

collections/README.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ the same elements, and the queries are exactly the same. Below we explain the me
1111
* batch_get 50. Find 50 elements from the collection.
1212
* batch_put 50. Insert 50 elements to the collection.
1313
* batch_remove 50. Remove 50 elements from the collection.
14+
* upgrade. Upgrade the canister with the same Wasm module. The map state is persisted by serializing and deserializing states into stable memory.
1415

1516
## **💎 Takeaways**
1617

@@ -22,7 +23,12 @@ the same elements, and the queries are exactly the same. Below we explain the me
2223
> **Note**
2324
>
2425
> * The Candid interface of the benchmark is minimal, therefore the serialization cost is negligible in this measurement.
25-
> * Due to the instrumentation overhead and cycle limit, we cannot profile computations with large collections. Hopefully, when deterministic time slicing is ready, we can measure the performance on larger memory footprint.
26+
> * Due to the instrumentation overhead and cycle limit, we cannot profile computations with very large collections.
27+
> * The `upgrade` column uses Candid for serializing stable data. In Rust, you may get better cycle cost by using a different serialization format. Another slowdown in Rust is that `ic-stable-structures` tends to be slower than the region memory in Motoko.
28+
> * Different library has different ways for persisting data during upgrades, there are mainly three categories:
29+
> + Use stable variable directly in Motoko: `zhenya_hashmap`, `btree`, `vector`
30+
> + Expose and serialize external state (`share/unshare` in Motoko, `candid::Encode` in Rust): `rbtree`, `heap`, `btreemap_rs`, `hashmap_rs`, `heap_rs`, `vector_rs`
31+
> + Use pre/post-upgrade hooks to convert data into an array: `hashmap`, `splay`, `triemap`, `buffer`, `imrc_hashmap_rs`
2632
> * `hashmap` uses amortized data structure. When the initial capacity is reached, it has to copy the whole array, thus the cost of `batch_put 50` is much higher than other data structures.
2733
> * `btree` comes from [mops.one/stableheapbtreemap](https://mops.one/stableheapbtreemap).
2834
> * `zhenya_hashmap` comes from [mops.one/map](https://mops.one/map).

collections/motoko/src/ZhenyaHashmap.mo

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,11 @@ import Hash "mo:base/Hash";
44
import Iter "mo:base/Iter";
55
import Option "mo:base/Option";
66
import Random "random";
7+
import Profiling "../../../utils/motoko/Profiling";
78

89
actor {
10+
stable let profiling = Profiling.init();
11+
912
func f_hash(x : Nat64) : Nat32 = Hash.hash(Nat64.toNat x);
1013
let hash : HashMap.HashUtils<Nat64> = (f_hash, Nat64.equal);
1114
stable var map = HashMap.new<Nat64, Nat64>();

collections/motoko/src/btreemap.mo

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,11 @@ import Nat64 "mo:base/Nat64";
33
import Iter "mo:base/Iter";
44
import Option "mo:base/Option";
55
import Random "random";
6+
import Profiling "../../../utils/motoko/Profiling";
67

78
actor {
9+
stable let profiling = Profiling.init();
10+
811
stable var map = Map.init<Nat64, Nat64>(null);
912
let rand = Random.new(null, 42);
1013

collections/motoko/src/buffer.mo

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,20 @@ import Iter "mo:base/Iter";
33
import Random "random";
44
import Nat64 "mo:base/Nat64";
55
import Option "mo:base/Option";
6+
import Profiling "../../../utils/motoko/Profiling";
67

78
actor {
9+
stable let profiling = Profiling.init();
10+
811
var buffer = Buffer.Buffer<Nat64>(0);
12+
stable var stableBuffer : [Nat64] = [];
13+
14+
system func preupgrade() {
15+
stableBuffer := Buffer.toArray(buffer);
16+
};
17+
system func postupgrade() {
18+
buffer := Buffer.fromArray(stableBuffer);
19+
};
920

1021
public func generate(n: Nat) : async () {
1122
buffer.clear();

collections/motoko/src/hashmap.mo

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,23 @@ import Hash "mo:base/Hash";
55
import Iter "mo:base/Iter";
66
import Option "mo:base/Option";
77
import Random "random";
8+
import Profiling "../../../utils/motoko/Profiling";
89

910
actor {
11+
stable let profiling = Profiling.init();
12+
1013
func hash(x: Nat64) : Nat32 = Hash.hash(Nat64.toNat x);
1114
var map = HashMap.HashMap<Nat64, Nat64>(0, Nat64.equal, hash);
15+
stable var stableMap: [(Nat64, Nat64)] = [];
1216
let rand = Random.new(null, 42);
1317

18+
system func preupgrade() {
19+
stableMap := Iter.toArray(map.entries())
20+
};
21+
system func postupgrade() {
22+
map := HashMap.fromIter(stableMap.vals(), stableMap.size(), Nat64.equal, hash);
23+
};
24+
1425
public func generate(size: Nat32) : async () {
1526
let rand = Random.new(?size, 1);
1627
let iter = Iter.map<Nat64, (Nat64, Nat64)>(rand, func x = (x, x));

collections/motoko/src/heap.mo

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,21 @@ import Iter "mo:base/Iter";
44
import Option "mo:base/Option";
55
import Random "random";
66
import O "mo:base/Order";
7+
import Profiling "../../../utils/motoko/Profiling";
78

89
actor {
10+
stable let profiling = Profiling.init();
11+
912
var map = Heap.Heap<Nat64>(Nat64.compare);
13+
stable var stableMap : Heap.Tree<Nat64> = null;
1014
let rand = Random.new(null, 42);
15+
16+
system func preupgrade() {
17+
stableMap := map.share();
18+
};
19+
system func postupgrade() {
20+
map.unsafeUnshare(stableMap);
21+
};
1122

1223
public func generate(size: Nat32) : async () {
1324
let rand = Random.new(?size, 1);

collections/motoko/src/rbtree.mo

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,22 @@ import Nat64 "mo:base/Nat64";
33
import Iter "mo:base/Iter";
44
import Option "mo:base/Option";
55
import Random "random";
6+
import Profiling "../../../utils/motoko/Profiling";
67

78
actor {
9+
stable let profiling = Profiling.init();
10+
811
var map = RBTree.RBTree<Nat64, Nat64>(Nat64.compare);
12+
stable var stableMap : RBTree.Tree<Nat64, Nat64> = #leaf;
913
let rand = Random.new(null, 42);
1014

15+
system func preupgrade() {
16+
stableMap := map.share();
17+
};
18+
system func postupgrade() {
19+
map.unshare(stableMap);
20+
};
21+
1122
public func generate(size: Nat32) : async () {
1223
let rand = Random.new(?size, 1);
1324
let iter = Iter.map<Nat64, (Nat64, Nat64)>(rand, func x = (x, x));

0 commit comments

Comments
 (0)