Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Stack size under Mono

I have written a tiny recursive bit of F# code to see how many levels of recursion I can fit onto the stack under .NET/Mono. It just prints the recursion depth whenever it is an exact power of 2, so I find out the maximum depth to within a factor 2.

I start the code in a thread with a defined amount of stack space using System.Threading.Thread (ThreadStart, int). Under .Net it seems to take approx 100 bytes per level of recursion, and I can get about 16 million levels on a 2G stack. The memory usage is broadly similar under Mono, however I can only get about 30 thousand levels. Increasing the stack size value passed to Thread past over about 600000 does not increase the recursion depth.

ulimit reports the stack size limit is 1G.

An obvious explanation is that Mono will not obey the second argument of Thread if it is too large. Does anybody please know how to convince Mono to allocate a large stack?

The code is trivial, but it's below just in case someone cares:

let rec f i =
    if popcount i = 1 then // population count is one on exact powers of 2
        printf "Got up to %d\n" i
        stdout.Flush ()
    if i = 1000000000 then 0 else 1 + f (i+1)
like image 216
Joe Huha Avatar asked Nov 06 '13 16:11

Joe Huha


1 Answers

Option 1: Change Mono Stack Size

An obvious explanation is that Mono will not obey the second argument of Thread if it is too large. Does anybody please know how to convince Mono to allocate a large stack?

You are correct that Mono will limit the stack size, even if you pass in a large value. For example, on my Cent OS 64-bit test machine, the maximum stack size that Mono will allocate is 2 megabytes. The Mono C# source file Thread.cs shows us what happens when you create a Mono thread:

public Thread (ThreadStart start, int maxStackSize)
{
    if (start == null)
        throw new ArgumentNullException ("start");

    threadstart = start;
    Internal.stack_size = CheckStackSize (maxStackSize);
}

static int CheckStackSize (int maxStackSize)
{
    if (maxStackSize < 0)
        throw new ArgumentOutOfRangeException ("less than zero", "maxStackSize");

    if (maxStackSize < 131072) // make sure stack is at least 128k big
        return 131072;

    int page_size = Environment.GetPageSize ();

    if ((maxStackSize % page_size) != 0) // round up to a divisible of page size
        maxStackSize = (maxStackSize / (page_size - 1)) * page_size;

    int default_stack_size = (IntPtr.Size / 4) * 1024 * 1024; // from wthreads.c
    if (maxStackSize > default_stack_size)
        return default_stack_size;

    return maxStackSize; 
}

The code above puts a hard limit on the stack size.

You could in theory change code in one or both of the above functions (bold lines) so that a larger stack size is allocated. Once you did this you would have to build the Mono runtime and then run your function to see if the change makes a difference.

I should stress that I do not know enough about Mono to understand if allocating a larger stack will help in your specific case. I would only do this as a last resort (if neither of my other answers work).

like image 129
chue x Avatar answered Sep 23 '22 01:09

chue x