-
Notifications
You must be signed in to change notification settings - Fork 98
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Memory Reserve for Queries and Upgrades (#4158)
# Memory Reserve for Queries and Upgrades ## Current Situation With the incremental GC, programs can scale to the full 4GB memory space. As a consequence, update calls can allocate the full memory space, such that even a simple query, a simple composite query, or a simple upgrade logic can no longer succeed. This could also happen with classical non-copying GCs if deterministic time slicing is sufficiently extended. ## Provisional Solution This PR prevents update calls (including canister initialization, heartbeats, and timers) from allocating the full memory by leaving a reserve for queries, composite queries, and canister upgrades. During queries, composite queries, and canister upgrades, garbage collection is suspended, such that the reserve is available to the mutator code. Callbacks of composite queries can also use the memory reserve. The current allocation limit for upgrade calls is 3.75 GB and applies to all GCs. This gives a reserve of 224 MB for the incremental GC as the last 32MB partition is unallocated in the current design. The scheduling heuristics of the incremental and generational GC needs to consider the reduced capacity for determining memory shortage. This PR can be viewed as a temporary measure until a memory reserve is implemented in the IC runtime system. ## Important Note The memory reserve may **not** be sufficient for a complex canister upgrade logic or large amount of stable heap data. Moreover, the upgrade logic may exceed the instruction limit. Thorough upgrade testing is required for canisters in any case.
- Loading branch information
1 parent
c8b4125
commit 01e2f02
Showing
26 changed files
with
275 additions
and
28 deletions.
There are no files selected for viewing
This file contains 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 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 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 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 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 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 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 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 |
---|---|---|
@@ -1,6 +1,6 @@ | ||
ingress Completed: Reply: 0x4449444c016c01b3c4b1f204680100010a00000000000000000101 | ||
ingress Completed: Reply: 0x4449444c0000 | ||
debug.print: {cycles = 2_389_389; size = +59_652} | ||
debug.print: {cycles = 2_389_400; size = +59_652} | ||
ingress Completed: Reply: 0x4449444c0000 | ||
debug.print: {cycles = 102_989_128; size = +1_817_872} | ||
debug.print: {cycles = 102_989_425; size = +1_817_872} | ||
ingress Completed: Reply: 0x4449444c0000 |
This file contains 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 |
---|---|---|
@@ -1,6 +1,6 @@ | ||
ingress Completed: Reply: 0x4449444c016c01b3c4b1f204680100010a00000000000000000101 | ||
ingress Completed: Reply: 0x4449444c0000 | ||
debug.print: {cycles = 2_493_575; size = +59_652} | ||
debug.print: {cycles = 2_493_587; size = +59_652} | ||
ingress Completed: Reply: 0x4449444c0000 | ||
debug.print: {cycles = 103_046_049; size = +1_817_872} | ||
debug.print: {cycles = 103_046_373; size = +1_817_872} | ||
ingress Completed: Reply: 0x4449444c0000 |
This file contains 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 |
---|---|---|
@@ -1,5 +1,5 @@ | ||
ingress Completed: Reply: 0x4449444c016c01b3c4b1f204680100010a00000000000000000101 | ||
ingress Completed: Reply: 0x4449444c0000 | ||
debug.print: (50_227, +30_261_252, 620_394_287) | ||
debug.print: (50_070, +32_992_212, 671_304_488) | ||
debug.print: (50_227, +30_261_252, 620_399_314) | ||
debug.print: (50_070, +32_992_212, 671_309_966) | ||
ingress Completed: Reply: 0x4449444c0000 |
This file contains 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 |
---|---|---|
@@ -1,5 +1,5 @@ | ||
ingress Completed: Reply: 0x4449444c016c01b3c4b1f204680100010a00000000000000000101 | ||
ingress Completed: Reply: 0x4449444c0000 | ||
debug.print: (50_227, +30_261_252, 667_797_463) | ||
debug.print: (50_070, +32_992_212, 720_521_360) | ||
debug.print: (50_227, +30_261_252, 667_802_947) | ||
debug.print: (50_070, +32_992_212, 720_527_336) | ||
ingress Completed: Reply: 0x4449444c0000 |
This file contains 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,6 @@ | ||
# INCREMENTAL-GC-ONLY | ||
# SKIP ic-ref-run | ||
install $ID memory-reserve-composite/memory-reserve-composite.mo "" | ||
ingress $ID prepare1 "DIDL\x00\x00" | ||
ingress $ID prepare2 "DIDL\x00\x00" | ||
query $ID allocateInCompositeQuery "DIDL\x00\x00" |
39 changes: 39 additions & 0 deletions
39
test/run-drun-non-ci/memory-reserve-composite/memory-reserve-composite.mo
This file contains 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,39 @@ | ||
import Prim "mo:⛔"; | ||
actor { | ||
stable var stableData = Prim.Array_tabulate<Nat>(1024 * 1024, func(index) { index }); | ||
var array0 : [var Nat] = [var]; | ||
var array1 : [var Nat] = [var]; | ||
var array2 : [var Nat] = [var]; | ||
var array3 : [var Nat] = [var]; | ||
Prim.debugPrint("Initialized " # debug_show (Prim.rts_memory_size())); | ||
|
||
public func prepare1() : async () { | ||
array0 := Prim.Array_init<Nat>(256 * 1024 * 1024, 0); // 1GB | ||
array1 := Prim.Array_init<Nat>(256 * 1024 * 1024, 1); // 2GB | ||
Prim.debugPrint("Prepared1 " # debug_show (Prim.rts_memory_size())); | ||
}; | ||
|
||
public func prepare2() : async () { | ||
array2 := Prim.Array_init<Nat>(256 * 1024 * 1024, 2); // 3GB | ||
array3 := Prim.Array_init<Nat>(150 * 1024 * 1024, 3); // around 3.75GB | ||
Prim.debugPrint("Prepared2 " # debug_show (Prim.rts_memory_size())); | ||
}; | ||
|
||
public composite query func allocateInCompositeQuery() : async () { | ||
ignore Prim.Array_init<Nat>(50 * 1024 * 1024, 4); | ||
Prim.debugPrint("Composite query call " # debug_show (Prim.rts_memory_size())); | ||
assert (Prim.rts_memory_size() > 3840 * 1024 * 1024); | ||
await nestedQuery(); | ||
ignore Prim.Array_init<Nat>(5 * 1024 * 1024, 4); | ||
Prim.debugPrint("Composite query callback " # debug_show (Prim.rts_memory_size())); | ||
assert (Prim.rts_memory_size() > 3840 * 1024 * 1024); | ||
}; | ||
|
||
public query func nestedQuery() : async () { | ||
Prim.debugPrint("Nested query " # debug_show (Prim.rts_memory_size())); | ||
}; | ||
}; | ||
|
||
//SKIP run | ||
//SKIP run-ir | ||
//SKIP run-low |
This file contains 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,6 @@ | ||
# INCREMENTAL-GC-ONLY | ||
# SKIP ic-ref-run | ||
install $ID memory-reserve-query/memory-reserve-query.mo "" | ||
ingress $ID prepare1 "DIDL\x00\x00" | ||
ingress $ID prepare2 "DIDL\x00\x00" | ||
query $ID allocateInQuery "DIDL\x00\x00" |
31 changes: 31 additions & 0 deletions
31
test/run-drun-non-ci/memory-reserve-query/memory-reserve-query.mo
This file contains 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,31 @@ | ||
import Prim "mo:⛔"; | ||
actor { | ||
stable var stableData = Prim.Array_tabulate<Nat>(1024 * 1024, func(index) { index }); | ||
var array0 : [var Nat] = [var]; | ||
var array1 : [var Nat] = [var]; | ||
var array2 : [var Nat] = [var]; | ||
var array3 : [var Nat] = [var]; | ||
Prim.debugPrint("Initialized " # debug_show (Prim.rts_memory_size())); | ||
|
||
public func prepare1() : async () { | ||
array0 := Prim.Array_init<Nat>(256 * 1024 * 1024, 0); // 1GB | ||
array1 := Prim.Array_init<Nat>(256 * 1024 * 1024, 1); // 2GB | ||
Prim.debugPrint("Prepared1 " # debug_show (Prim.rts_memory_size())); | ||
}; | ||
|
||
public func prepare2() : async () { | ||
array2 := Prim.Array_init<Nat>(256 * 1024 * 1024, 2); // 3GB | ||
array3 := Prim.Array_init<Nat>(150 * 1024 * 1024, 3); // around 3.75GB | ||
Prim.debugPrint("Prepared2 " # debug_show (Prim.rts_memory_size())); | ||
}; | ||
|
||
public query func allocateInQuery() : async () { | ||
ignore Prim.Array_init<Nat>(50 * 1024 * 1024, 4); | ||
Prim.debugPrint("Query call " # debug_show (Prim.rts_memory_size())); | ||
assert (Prim.rts_memory_size() > 3840 * 1024 * 1024); | ||
}; | ||
}; | ||
|
||
//SKIP run | ||
//SKIP run-ir | ||
//SKIP run-low |
This file contains 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,6 @@ | ||
# INCREMENTAL-GC-ONLY | ||
# SKIP ic-ref-run | ||
install $ID memory-reserve-update/memory-reserve-update.mo "" | ||
ingress $ID prepare1 "DIDL\x00\x00" | ||
ingress $ID prepare2 "DIDL\x00\x00" | ||
ingress $ID allocateInUpdate "DIDL\x00\x00" |
30 changes: 30 additions & 0 deletions
30
test/run-drun-non-ci/memory-reserve-update/memory-reserve-update.mo
This file contains 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,30 @@ | ||
import Prim "mo:⛔"; | ||
actor { | ||
stable var stableData = Prim.Array_tabulate<Nat>(1024 * 1024, func(index) { index }); | ||
var array0 : [var Nat] = [var]; | ||
var array1 : [var Nat] = [var]; | ||
var array2 : [var Nat] = [var]; | ||
var array3 : [var Nat] = [var]; | ||
Prim.debugPrint("Initialized " # debug_show (Prim.rts_memory_size())); | ||
|
||
public func prepare1() : async () { | ||
array0 := Prim.Array_init<Nat>(256 * 1024 * 1024, 0); // 1GB | ||
array1 := Prim.Array_init<Nat>(256 * 1024 * 1024, 1); // 2GB | ||
Prim.debugPrint("Prepared1 " # debug_show (Prim.rts_memory_size())); | ||
}; | ||
|
||
public func prepare2() : async () { | ||
array2 := Prim.Array_init<Nat>(256 * 1024 * 1024, 2); // 3GB | ||
array3 := Prim.Array_init<Nat>(150 * 1024 * 1024, 3); // around 3.75GB | ||
Prim.debugPrint("Prepared2 " # debug_show (Prim.rts_memory_size())); | ||
}; | ||
|
||
public func allocateInUpdate() : async () { | ||
Prim.debugPrint("Update call " # debug_show (Prim.rts_memory_size())); | ||
ignore Prim.Array_init<Nat>(50 * 1024 * 1024, 4); | ||
}; | ||
}; | ||
|
||
//SKIP run | ||
//SKIP run-ir | ||
//SKIP run-low |
This file contains 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,6 @@ | ||
# INCREMENTAL-GC-ONLY | ||
# SKIP ic-ref-run | ||
install $ID memory-reserve-upgrade/memory-reserve-upgrade.mo "" | ||
ingress $ID prepare1 "DIDL\x00\x00" | ||
ingress $ID prepare2 "DIDL\x00\x00" | ||
upgrade $ID memory-reserve-upgrade/memory-reserve-upgrade.mo "" |
25 changes: 25 additions & 0 deletions
25
test/run-drun-non-ci/memory-reserve-upgrade/memory-reserve-upgrade.mo
This file contains 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,25 @@ | ||
import Prim "mo:⛔"; | ||
actor { | ||
stable var stableData = Prim.Array_tabulate<Nat>(1024 * 1024, func(index) { index }); | ||
var array0 : [var Nat] = [var]; | ||
var array1 : [var Nat] = [var]; | ||
var array2 : [var Nat] = [var]; | ||
var array3 : [var Nat] = [var]; | ||
Prim.debugPrint("Initialized " # debug_show (Prim.rts_memory_size())); | ||
|
||
public func prepare1() : async () { | ||
array0 := Prim.Array_init<Nat>(256 * 1024 * 1024, 0); // 1GB | ||
array1 := Prim.Array_init<Nat>(256 * 1024 * 1024, 1); // 2GB | ||
Prim.debugPrint("Prepared1 " # debug_show (Prim.rts_memory_size())); | ||
}; | ||
|
||
public func prepare2() : async () { | ||
array2 := Prim.Array_init<Nat>(256 * 1024 * 1024, 2); // 3GB | ||
array3 := Prim.Array_init<Nat>(150 * 1024 * 1024, 3); // around 3.75GB | ||
Prim.debugPrint("Prepared2 " # debug_show (Prim.rts_memory_size())); | ||
}; | ||
}; | ||
|
||
//SKIP run | ||
//SKIP run-ir | ||
//SKIP run-low |
This file contains 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 @@ | ||
ingress Completed: Reply: 0x4449444c016c01b3c4b1f204680100010a00000000000000000101 | ||
debug.print: Initialized 33_554_432 | ||
ingress Completed: Reply: 0x4449444c0000 | ||
debug.print: Prepared1 2_248_146_944 | ||
ingress Completed: Reply: 0x4449444c0000 | ||
debug.print: Prepared2 4_026_531_840 | ||
ingress Completed: Reply: 0x4449444c0000 | ||
debug.print: Composite query call 4_261_412_864 | ||
debug.print: Nested query 4_026_531_840 | ||
debug.print: Composite query callback 4_261_412_864 | ||
Ok: Reply: 0x4449444c0000 |
Oops, something went wrong.