Any way to know how much memory has been allocated on the stack?

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)
}

1 Like