• interp alias perfomance

    From oleg.o.nemanov@gmail.com@21:1/5 to All on Fri Oct 1 07:08:54 2021
    Hi, all.

    I've done the next experiment with alias performance measurement:

    % proc test {} { set a 1; }
    % proc test1 {} { test; }
    % interp alias {} test2 {} test
    test2
    % time test 1000000
    0.426097 microseconds per iteration
    % time test1 1000000
    0.656562 microseconds per iteration
    % time test2 1000000
    0.755594 microseconds per iteration

    I thought that alias performance is between proc and proc wrapper. May be i used something wrong? Is there solution to give a proc just an alias(a second name) which point to the same code(and thus give the same performance)?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Donal K. Fellows@21:1/5 to oleg.o....@gmail.com on Fri Oct 1 09:12:20 2021
    On Friday, 1 October 2021 at 15:08:57 UTC+1, oleg.o....@gmail.com wrote:
    I thought that alias performance is between proc and proc wrapper. May be i used something wrong? Is there solution to give a proc just an alias(a second name) which point to the same code(and thus give the same performance)?

    (On my machine, the two test case speeds are quite a bit closer. No idea why.)

    I'd guess that what the alias gains in not having to manipulate a stack frame it loses in the complexity for passing through arguments. If you want to do something more comparable in terms of functionality, try with this:

    proc test3 args {test {*}$args}

    I find that to be slower than the other examples (using tailcall as well makes it even slower still).

    Donal.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From oleg.o.nemanov@gmail.com@21:1/5 to All on Fri Oct 1 10:55:35 2021
    пятница, 1 октября 2021 г. в 19:12:22 UTC+3, Donal K. Fellows:
    (On my machine, the two test case speeds are quite a bit closer. No idea why.)

    Yes. If i convert test1 into proc with arguments(like your test3), then it speed is the same as of test2.

    I'd guess that what the alias gains in not having to manipulate a stack frame it loses in the complexity for passing through arguments. If you want to do something more comparable in terms of functionality, try with this:

    proc test3 args {test {*}$args}

    Now speed of proc wrapper is equal to alias speed :-)(it slow like an alias).


    I find that to be slower than the other examples (using tailcall as well makes it even slower still).

    Hm. So, at now we have no way to make an alias/link to the same proc body, right? May be some "procalias" proc :-)?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Jonathan Kelly@21:1/5 to oleg.o....@gmail.com on Sun Oct 3 15:48:09 2021
    On 10/2/21 00:08, oleg.o....@gmail.com wrote:
    Hi, all.

    I've done the next experiment with alias performance measurement:

    % proc test {} { set a 1; }
    % proc test1 {} { test; }
    % interp alias {} test2 {} test
    test2
    % time test 1000000
    0.426097 microseconds per iteration
    % time test1 1000000
    0.656562 microseconds per iteration
    % time test2 1000000
    0.755594 microseconds per iteration

    I thought that alias performance is between proc and proc wrapper. May be i used something wrong? Is there solution to give a proc just an alias(a second name) which point to the same code(and thus give the same performance)?


    If fractions of a microsecond are significant, I'd suggest TCL is the
    wrong tool.

    J

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From oleg.o.nemanov@gmail.com@21:1/5 to All on Mon Oct 4 05:14:49 2021
    Colleagues, please look at this:

    static int
    procalias(ClientData cdata, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
    {
    Tcl_CmdInfo info;

    if (objc != 3) {
    Tcl_SetObjResult(interp, Tcl_NewStringObj("Wrong number of arguments", -1));
    return TCL_ERROR;
    }
    if (Tcl_GetCommandInfo(interp, Tcl_GetString(objv[2]), &info)) {
    if (info.isNativeObjectProc)
    Tcl_CreateObjCommand(interp, Tcl_GetString(objv[1]), info.objProc, info.objClientData, NULL);
    else
    Tcl_CreateCommand(interp, Tcl_GetString(objv[1]), info.proc, info.clientData, NULL);
    } else {
    Tcl_SetObjResult(interp, Tcl_ObjPrintf("There is no command: %s", Tcl_GetString(objv[2])));
    return TCL_ERROR;
    }
    return TCL_OK;
    }

    ...
    Tcl_CreateObjCommand(interp, "procalias", procalias, NULL, NULL);

    Is this can be used in production code or i missed something?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From oleg.o.nemanov@gmail.com@21:1/5 to All on Mon Oct 4 05:45:01 2021
    Sorry. The indentation was eaten.

    static int
    procalias(ClientData cdata, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
    {
    Tcl_CmdInfo info;

    if (objc != 3) {
    Tcl_SetObjResult(interp, Tcl_NewStringObj("Wrong number of arguments", -1));
    return TCL_ERROR;
    }
    if (Tcl_GetCommandInfo(interp, Tcl_GetString(objv[2]), &info)) {
    if (info.isNativeObjectProc)
    Tcl_CreateObjCommand(interp, Tcl_GetString(objv[1]), info.objProc, info.objClientData, NULL);
    else
    Tcl_CreateCommand(interp, Tcl_GetString(objv[1]), info.proc, info.clientData, NULL);
    } else {
    Tcl_SetObjResult(interp, Tcl_ObjPrintf("There is no command: %s", Tcl_GetString(objv[2])));
    return TCL_ERROR;
    }
    return TCL_OK;
    }

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Donal K. Fellows@21:1/5 to Oleg O. Nemanov on Thu Oct 7 12:53:26 2021
    On Monday, 4 October 2021 at 13:14:51 UTC+1, Oleg O. Nemanov wrote:
    Is this can be used in production code or i missed something?

    It's unsafe because the lifetime of the value in the clientData field (well, the lifetime of the structure it points to) isn't being handled right. You'd get away with it in production code, but *only* if the target command lives at least as long as the
    alias. If both parts are implemented in code you control, that's trivially handled by reference counting the structure (and arguably it becomes two equivalent names for the one thing). If not, only the high level guarantees of how you write your script
    will save you from a nasty crash (or rather it's use-after-free undefined behaviour; all bets are off).

    The safer thing with general aliasing is to dispatch indirectly (Tcl_EvalObjv is the most direct route into this) but then you've got the additional costs of more memory management as well as copying the argument references.

    Donal.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Oleg O. Nemanov@21:1/5 to All on Tue Oct 12 02:16:22 2021
    четверг, 7 октября 2021 г. в 22:53:28 UTC+3, Donal K. Fellows:
    On Monday, 4 October 2021 at 13:14:51 UTC+1, Oleg O. Nemanov wrote:
    Is this can be used in production code or i missed something?
    It's unsafe because the lifetime of the value in the clientData field (well, the lifetime of the structure it points to) isn't being handled right. You'd get away with it in production code, but *only* if the target command lives at least as long as
    the alias. If both parts are implemented in code you control, that's trivially handled by reference counting the structure (and arguably it becomes two equivalent names for the one thing). If not, only the high level guarantees of how you write your
    script will save you from a nasty crash (or rather it's use-after-free undefined behaviour; all bets are off).

    I see. Thanks!

    The safer thing with general aliasing is to dispatch indirectly (Tcl_EvalObjv is the most direct route into this) but then you've got the additional costs of more memory management as well as copying the argument references.

    And this will be the same speed as pure tcl test3 proc?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Donal K. Fellows@21:1/5 to Oleg O. Nemanov on Tue Oct 12 03:50:36 2021
    On Tuesday, 12 October 2021 at 10:16:25 UTC+1, Oleg O. Nemanov wrote:
    And this will be the same speed as pure tcl test3 proc?

    Perhaps a little faster, depending on how you write it. Not needing to allocate and initialise a Tcl stack frame will be a win, but you might trip something else. You'll need to write it and time it to be sure.

    Donal.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Andreas Leitgeb@21:1/5 to oleg.o....@gmail.com on Thu Jan 27 17:27:27 2022
    oleg.o....@gmail.com <oleg.o.nemanov@gmail.com> wrote:
    I've done the next experiment with alias performance measurement:
    % proc test {} { set a 1; }
    % proc test1 {} { test; }
    % interp alias {} test2 {} test
    test2
    % time test 1000000
    0.426097 microseconds per iteration
    % time test1 1000000
    0.656562 microseconds per iteration
    % time test2 1000000
    0.755594 microseconds per iteration

    One more thing to compare:

    have a look at https://wiki.tcl-lang.org/page/namespace
    and search for section "Make an Alias for a Command"

    paste the procedure "alias" into your shell or script,
    and then try:

    % alias test test3
    % time test3 1000000

    my timings here: (I made two runs of each and round the average to two digits) test: 0.41
    test1: 0.65
    test2: 0.71
    test3: 0.50

    PS:
    I'm aware that this topic is ~3 months old. - I wouldn't miss a
    chance to re-raise awareness for this, in the hope, that either
    interp alias would be special-cased for "same-interp and no extra
    args" to do the optimization, or that "namespace alias" gets added
    to Tcl core ;-)

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)