[Gambas-user] Are GoSubs efficient?

Tobias Boege taboege at gmail.com
Mon Apr 22 21:18:47 CEST 2019


On Mon, 22 Apr 2019, Cedron Dawg wrote:
> I'm a big fan of GoSubs.  See my last post in
> 
> https://forum.gambas.one/viewtopic.php?f=4&t=694
> 
> The question I have about GoSubs in Gambas is how lightweight are they compared to a regular sub call?
> 

At the bytecode level, GoSub compiles to a single instruction, whereas
a call is at least two. This nonsensical piece of code

  Public Function f(a As Integer, b As Integer) As Integer
  _Next:
    Dec a
    GoSub _Next
    f(a, b - 1)
  End

for example becomes

  0000 :  02FE            PUSH PARAM -2
  0001 :  AFFF            ADD QUICK -1
  0002 :  0AFE            POP PARAM -2
  0003 :  2300 FFFB       GOSUB 0000
  0005 :  B803            PUSH FUNCTION f
  0006 :  02FE            PUSH PARAM -2
  0007 :  02FF            PUSH PARAM -1
  0008 :  AFFF            ADD QUICK -1
  0009 :  1C02            CALL (2)
  0010 :  1A01            DROP (1)
  0011 :  1002            RETURN (2)

As for the runtime overhead, GOSUB at [1] is literally saving some context,
including the instruction pointer, followed by a GOTO. The CALL instruction
at [2] is obviously more complicated.

Whereas the GoSub target offset is encoded in the instruction, pretty much
every form of CALL requires some kind of lookup in the current context and
parameter checks.

Finally, running these two, hopefully comparable enough [*], implementations
of the identity function:

  Public Function f(b As Integer) As Integer
    Dim a As Integer
  _Inc:
    Inc a
    Dec b
    If b Then GoSub _Inc
    Return a
  End

  Public Function g(b As Integer) As Integer
    If Not b Then Return b
    Return 1 + g(b - 1)
  End

each with argument 10e4 and 10e4 times, I get the following timings in
milliseconds:

  3115
  4246

Regards,
Tobi

[1] https://gitlab.com/gambas/gambas/blob/master/main/gbx/gbx_exec_loop.c#L940
[2] https://gitlab.com/gambas/gambas/blob/master/main/gbx/gbx_exec_loop.c#L1059

[*] For example, I took care not to have g allocate a new local variable
    on each call, because f doesn't do that. Both do two additions per
    "iteration" and have a single conditional.

-- 
"There's an old saying: Don't change anything... ever!" -- Mr. Monk


More information about the User mailing list