On Fri, Mar 1, 2019 at 8:13 AM Jason E. Aten <
j.e....@gmail.com> wrote:
>
> If I include a chunk of assembly .s code in my Go code, does my program pay the CGO transition cost of locking and changing to a C stack?
No. The assembly function is simply called just as a Go function is called.
> I'm pretty sure the answer is no. But my knowledge of the Go internals is low enough that I thought I would like confirm that before I go pulling in .s code.
>
> Then for numerical work, if I need to call some Fortran 90 compiled library routines, does it not just look like assembly? I suppose not... in the sense that it makes certain assumptions about being able to grow the stack it is running on without running out of space. Are there assumptions beyond the stack that are used? Probably some "standard library" runtime dependencies?
Go assembly code is compiled by the Go assembler, cmd/asm. The author
of the assembly code is required to specify how much stack space the
assembly function requires, in the TEXT pseudo-op that introduces the
function. For more about this, see
https://golang.org/doc/asm. The
cmd/asm program will use that user declaration to insert a function
prologue that ensures that enough stack space is available, copying
the stack if necessary. The cmd/asm program will also produce a stack
map that the garbage collector will use when tracing back the stack;
in practice it's quite difficult for the assembler code to define this
stack map as anything other than "this stack contains no pointers",
but see runtime/funcdata.h.
In any case, your Fortran 90 code will have none of that information.
Of course, if you know the exact stack usage of your Fortran code, and
if the code never stores pointers on the stack, then you could with
some effort write Go assembly code that defines the appropriate stack
information and then calls the Fortran code. I think that would, but
it would require a lot of manual hand-holding.
> So on to my central question: Can the CGO transition stack switching cost be minimized by telling Go to run my main (single threaded) Go routine on a C thread to start with? In other words, can I minimize the CGO switching cost by doing runtime.LockOSThread() or similar?
>
> > It seems like if we are already on a C thread, then perhaps *some large part* of the cost of Go -> f90 can be avoided. Of course the Go compiler doesn't know we are on a C thread in the general case, right(?), so it probably can't optimize those transitions by omitting change-the-stack code.
This doesn't work, because the runtime expects to be able to use the C
thread stack in some cases to handle scheduling between goroutines.
You can't run general Go code on that stack. Note that LockOSThread
does not cause code to run on the C thread stack. It causes the
goroutine to only be scheduled on that thread.
Also, while there is a cost to the fact that cgo changes stack, there
are larger costs to 1) telling the Go scheduler that the code is
leaving Go and entering C; 2) changing from the Go calling convention
to the C calling convention. Eliminating the stack switching costs,
while not entirely negligible, would not make cgo calls as fast as Go
calls.
> Returning to the original throught about .s code, what would happen if that code tried to grow the stack too far? Just crash? Is there guidance about how far assembly can grow the stack before it needs to check back with the runtime?
The assembly can grow the stack exactly as far as the TEXT declaration
said that the stack would grow. Any farther may lead to memory
corruption.
Ian