4 ms·
> and the stack is basically never freed Not true, stacks are still freed if utilisation drops below a certain percentage. > So there might be a one-time perf
by 4ad 11y ago
> and the stack is basically never freed
Not true, stacks are still freed if utilisation drops below a certain percentage.
> So there might be a one-time performance penalty on the first C call [...] in Go 1.3+ the existing stack is fine to use
Not true, contiguous stacks start even smaller than segmented stacks, also they can't be used for C code at all. Only type-safe code with stack maps can run on the goroutine stacks, because the precise garbage collector has to scan the stack and has to understand where on the stack there are pointers and where there aren't. C code breaks this requirement.
For calls into C, the thread stack is used, which in Go usually has 32kB, but varies on some platforms, for example on Windows, it's 256kB IIRC. The runtime switches the stack (which only takes a few instructions), does the ABI translation and calls the function.
The stack switching mechanism and ABI translation mechanism have trivial overhead, most of the overhead comes from runtime bookkeeping, e.g. the runtime must ensure there are always enough threads to run user-level Go code.
- geofft 11y ago> also they can't be used for C code at all. Only type-safe code with stack maps can run on the goroutine stacks, because the precise garbage collector has to scan the stack and has to understand where on the stack there are pointers and where there aren't. C code breaks this requirement. Is this still true of C code that doesn't call back into Go code, like libc itself? The Go garbage collector will never get triggered, and any Go code should treat anything below %esp after the call completes as uninitialized data. (Also, on Windows, don't actual system calls reuse the same stack, too?) It seems like if you wanted to design Go for dynamically linking to libc instead of making raw system calls, it wouldn't be difficult.
- 4ad 11y ago> Is this still true of C code that doesn't call back into Go code, like libc itself? The Go garbage collector will never get triggered, and any Go code should treat anything below %esp after the call completes as uninitialized data. I should give a more thorough explanation. If you call C code, the only way that would be useful is if we pass Go-allocated buffers to the C code. This only works if we pass to the C code untyped uintptr's, which must live on the stack because of garbage collector reasons. In your hypothetical world, you want to call C code on the g stacks. This can only works if the g stacks are copied into a larger stack. The stack copying mechanism inspects the stack map to see which pointers need updating. This stack map is also used by the garbage collector, but I shouldn't have mentioned it in my original post. The stack copying mechanism can't update the untyped uintptr's living on the stack, therefore you can't call C code on the g stack. There are other reasons why calling C code on the g stack would be a bad idea but I won't get into them. Final point is, C code is called on the system stack. > (Also, on Windows, don't actual system calls reuse the same stack, too?) Which stack and which system calls? On Windows, target calls are made on the g0 stack, which is the thread stack. These calls are just calls into regular C code, most of it in kernel32.dll, some of it in ntdll.dll. This C code will eventually do system calls. Those actual system calls don't need any stack.