<->
🤝*
.asm
fun yes = (print "yes"; yes)
<->
🤝-{💥}
.asm
Objectives
CakeML
Why do programs run out of memory?
-> dataLang
v = Number int
| Word64 word64
| Block ts tag (v list) -- ts = tag = num
| CodePtr num
| RefPtr num
〘
[1,2,3]
〙
Block 67 cons_tag [Number 1;
Block 66 cons_tag [Number 2;
Block 65 cons_tag [Number 3;
Block 0 nil_tag []]]]
is_space_safe(dataLang)
==>
sem(CakeML)
<->
sem(machine)
size_of_heap s <= s.limits.heap_limit
size_of_stack s <= s.limits.stack_limit
How do we count?
size_of_heap s
=
size_of reachabe_values s.refs {}
<|s.locals|> ++ <|s.stack|> ++ <|s.global|>
size_of_heap s =
size_of_heap (run_gc s)
size_of vals refs seen
Where:
vals
) is a list of v
valuesrefs
) is a mapping from numbers to valuesseen
) timestamps we have already seen〘[1,2,3]〙
Block 67 cons_tag [Number 1;
Block 66 cons_tag [Number 2;
Block 65 cons_tag [Number 3;
Block 0 nil_tag []]]]
size_of [〘[1,2,3]〙;〘[1,2,3]〙] refs seen
10 + size_of [〘[1,2,3]〙] refs ({67,66,65} ∪ seen)
10 + size_of [Block 67 ...] refs ({67,66,65} ∪ seen)
10 + 0
size_of vals refs seen
fun yes = (print "yes"; yes)
You can prove it!
It's complicated...
size_of 〘[2,...,n]〙 refs seen
<=
size_of 〘[1,2,..,n]〙 refs seen
size_of [Block 66 cons_tag [Number 2;...]] refs seen
<=
size_of [Block 67 cons_tag [Number 1;
Block 66 cons_tag [Number 2;...]]] refs seen
67 ∈ seen
67 ∈ seen
67 ∈ seen
size_of [Block 67 ...] refs seen = 0
size_of [Block 66 ...] refs seen
<=
size_of [Block 67 ...] refs seen
size_of [Block 66 ...] refs seen <= 0
67 ∉ seen
67 ∉ seen
size_of [Block 67 ...] ...
= 3 + size_of [Block 66 ...] refs ({67} ∪ seen)
67 ∉ seen
size_of [Block 67 ...] ...
= 3 + size_of [Block 66 ...] refs ({67} ∪ seen)
size_of [Block 66 ...] refs seen
<=
size_of [Block 66 ...] refs ({67} ∪ seen)
size_of [Block 66 ...] refs seen
<=
size_of [Block 66 ...] refs ({67} ∪ seen)
size_of [Block 66 cons_tag [Number 2;
Block 67 ...]]
refs seen
<=
size_of [Block 66 cons_tag [Number 2;
Block 67 ...]]
refs ({67} ∪ seen)
size_of vals refs seen
++
A flat reachability-based measure
flat_size_of refs blocks roots
Where:
refs
) is a mapping from numbers to valuesblocks
) is a mapping from timestamps to blocksroots
) is a list of "root" valuesblocks
67 |-> Block 67 ...
40 |-> Block 40 ...
10 |-> Block 10 ...
The set of all reachable values
<|s.locals|> ++ <|s.stack|> ++ <|s.global|>
[
Block 71 some_tag [Number 1; Block 74 ...];
Number 57;
Word64 0xF5CA15;
Word64 0x01368E;
Word64 0xC81026;
RefPtr 45;
Block 75 some_tag [RefPtr 84; ...];
]
The set of all reachable values addresses
addr = TStamp num -- Blocks
| RStamp num -- Pointers
to_addrs [] = ∅
to_addrs (Block ts _ _::xs) = {TStamp ts} ∪ to_addrs xs
to_addrs (RefPtr ptr ::xs) = {RStamp ts} ∪ to_addrs xs
to_addrs (_ ::xs) = to_addrs xs
to_addrs ([
Block 71 some_tag [Number 1; Block 74 ...];
Number 57;
Word64 0xF5CA15;
Word64 0x01368E;
Word64 0xC81026;
RefPtr 45;
Block 75 some_tag [RefPtr 84; ...];
])
{TStamp 71; RStamp 45; TStamp 75}
to_addrs ([
Block 71 some_tag [Number 1; Block 74 ...];
Number 57;
Word64 0xF5CA15;
Word64 0x01368E;
Word64 0xC81026;
RefPtr 45;
Block 75 some_tag [RefPtr 84; ...];
])
TStamp 71 -> TStamp 74
TStamp 75 -> RStamp 84
RStamp 45 -> ...
The set of all reachable addresses
=
reachable_addrs refs blocks roots =
{ y | ∃x. x ∈ roots ∧ x ->* y }
Now we measure!
flat_measure (Word64 _) = 3
flat_measure (Number i) =
if small_num i
then 0
else ... -- big num stuff
flat_measure _ = 0
RStamp 45
TStamp 50
RStamp 14
TStamp 75
->
->
->
->
[33,Block 43 ...]
[Ptr 30,Ptr 94]
[53,85,17]
[0xFF0D,0xAB0D,0xDD12]
RStamp 45
TStamp 50
RStamp 14
TStamp 75
->
->
->
->
3
2
6
12
Σ
RStamp 45
TStamp 50
RStamp 14
TStamp 75
->
->
->
->
3
2
6
12
23
addrs_measure refs blocks (TStamp ts) =
case lookup ts blocks of
| SOME (Block _ _ vs) =>
1 + LENGTH vs + SUM (MAP flat_measure vs)
| _ => 0
addrs_measure refs blocks (RStamp p) =
...
flat_size_of refs blocks roots =
SUM (MAP flat_measure roots) +
𝚺 (addrs_measure refs blocks)
(reachable_addrs refs blocks (to_addrs roots))
flat_size_of s.refs s.all_blocks 〘[2,...,n]〙
<=
flat_size_of s.refs s.all_blocks 〘[1,2,..,n]〙
a ⊆ b
==>
𝚺 f a <= 𝚺 f b
reachable_addrs refs blocks
[Block 66 ...]
⊆
reachable_addrs refs blocks
[Block 67 cons_tag [Number 1;
Block 66 ...]]
{TStamp 66; ...}
⊆
{TStamp 67;TStamp 66; ...}
flat_size_of refs blocks roots
flat_size_of refs blocks vals
size_of vals refs seen