Is there any way to know how much memory has been allocated on the stack?
– There is.
– Probably.
– This code snippet is misleading.
Here is my working example (took me 5 days of trial and error).
Notes:
It's not portable
You have to use the OS-specific procedures to get the stack info
It's not multithreaded
It’s done in the main thread
The thread's stack space is assumed to be used by the recursive procedure only
This assumption is wrong, so I used ~50kb as a safety margin
Windows version
package main
import "core:fmt"
foreign import lib {
"kernel32.lib",
}
foreign lib {
GetCurrentThreadStackLimits :: proc "c" (LowLimit: ^u64, HighLimit: ^u64) ---
}
rec_proc :: proc(p_dyn_arr: ^[dynamic]int, p_marker: ^int) {
marker: int
// your calculations
a, b: [64]uint
c := a + b
// If the work isn't done:
// 1) calculate the usage
size_used: int
switch len(p_dyn_arr) {
// If it's the first call - assume the size_used is zero
case 0:
// If it's the second call - correct the first call usage value
case 1:
p_dyn_arr[0] = abs(int(uintptr(p_marker) - uintptr(&marker)))
size_used = p_dyn_arr[0] * 2
// If it's the n-th call - the size_used is n times bigger
case:
size_used = p_dyn_arr[0] * (len(p_dyn_arr) + 1)
}
append(p_dyn_arr, size_used)
// 2) make another call if possible
dif := 0
if len(p_dyn_arr) > 1 {
dif = size_used - p_dyn_arr[len(p_dyn_arr) - 2]
}
if (size_used + dif < cap(p_dyn_arr)) {
fmt.printfln("calls made : %v; size used: %v",
len(p_dyn_arr), size_used)
rec_proc(p_dyn_arr, &marker)
} else {
fmt.printfln("Out of memory after %v call(s).", len(p_dyn_arr))
}
}
main :: proc() {
// Get the stack info
low_limit, high_limit: u64
GetCurrentThreadStackLimits(&low_limit, &high_limit)
// ~50kb is used as a safety margin
da := make([dynamic]int, 0, (high_limit - low_limit) - 50_000)
defer delete(da)
rec_proc(&da, nil)
}
Linux version
package main
import "core:fmt"
import "core:sys/linux"
rec_proc :: proc(p_dyn_arr: ^[dynamic]int, p_marker: ^int) {
marker: int
// your calculations
a, b: [64]uint
c := a + b
// If the work isn't done:
// 1) calculate the usage
size_used: int
switch len(p_dyn_arr) {
// If it's the first call - assume the size_used is zero
case 0:
// If it's the second call - correct the first call usage value
case 1:
p_dyn_arr[0] = abs(int(uintptr(p_marker) - uintptr(&marker)))
size_used = p_dyn_arr[0] * 2
// If it's the n-th call - the size_used is n times bigger
case:
size_used = p_dyn_arr[0] * (len(p_dyn_arr) + 1)
}
append(p_dyn_arr, size_used)
// 2) make another call if possible
dif := 0
if len(p_dyn_arr) > 1 {
dif = size_used - p_dyn_arr[len(p_dyn_arr) - 2]
}
if (size_used + dif < cap(p_dyn_arr)) {
fmt.printfln("calls made : %v; size used: %v",
len(p_dyn_arr), size_used)
rec_proc(p_dyn_arr, &marker)
} else {
fmt.printfln("Out of memory after %v call(s).", len(p_dyn_arr))
}
}
main :: proc() {
// Get the stack info
rlm: linux.RLimit
linux.getrlimit(linux.RLimit_Kind.STACK, &rlm)
// ~50kb is used as a safety margin
da := make([dynamic]int, 0, rlm.cur - 50_000)
defer delete(da)
rec_proc(&da, nil)
}