Howto:Vectorizing the Nasal setprop() API: Difference between revisions

From FlightGear wiki
Jump to navigation Jump to search
(→‎Objective: Fix typo)
Tags: Mobile edit Mobile web edit
Line 1: Line 1:
{{Stub}}
{{Stub}}


== Obbjective ==
== Objective ==
 
== Motivation ==
== Motivation ==
Making setprop() faster  
Making setprop() faster  

Revision as of 16:53, 30 December 2016

This article is a stub. You can help the wiki by expanding it.

Objective

Motivation

Making setprop() faster

Background

Let's consider the following snippet of code [1]:

    var path = my_graph._node.getPath();

    for (var i = 0; i< size(cmd); i=i+1)
    {
    index1 = 2 * i;
    index2 = index1+1;

    setprop(path~"/cmd["~i~"]", cmd[i]);
    setprop(path~"/coord["~index1~"]", coord[index1]);
    setprop(path~"/coord["~index2~"]", coord[index2]);
    }

This contains a single for-loop that ends up calling one Nasal extension function (setprop) 3 times per loop iteration. However, the overhead from switching between C and Nasal once per call can obviously add up, depending on the size of the cmd vector. Thus, we could greatly reduce this overhead by coming up a modified setprop() equivalent that directly operates on a path and vector accordingly:

    var path = my_graph._node.getPath();
    # cmd being a Nasal vector, the for-loop can be executed in native C code instead of requiring context switches: 
    setprop(path~"/cmd", cmd);

Understanding setprop()

One quick workaround would be providing a setprop() equivalent that directly works using Nasal vectors (arrays), i.e. which directly operate on vectors (think GLSL-like): setprop_vector("/foo/x", vector);

This would be the equivalent of the Nasal code shown above, just in C/C++ space - i.e. it would be a subset of the f_setprop() API: Howto:Extend Nasal

However, it's pretty much copy & paste actually - i.e. a new f_setpropv() function and adapting it to directly get the sie of the passed vector and use that in a for-loop to do indexed property updates directly - which should translate into N fewer C<->Nasal context switches, because it'd be all done in native C++ code at that point. We once did that to help speed up diff'ing two Nasal vectors in a fast way, and it caused a massive speed-up - I think it was James or Stuart who helped get that commited back then. [2]


// setprop() extension function.  Concatenates its string arguments as
// property names and sets the value of the specified property to the
// final argument.
static naRef f_setprop(naContext c, naRef me, int argc, naRef* args)
{
    // this checks if we have two arguments, and bails out if we don't
    if (argc < 2) {
        naRuntimeError(c, "setprop() expects at least 2 arguments");
    }

    // next, this will get the 2nd argument and store it as val
    naRef val = args[argc - 1];

    // this will look up the property matching the property path specified and store it as p
    // TODO: this can be further simplified for the vector use case
    SGPropertyNode* p = findnode(c, args, argc-1, true);

    bool result = false;
    try {
        // if the value is a Nasal string, set the property to be a string
        if(naIsString(val)) result = p->setStringValue(naStr_data(val));

        // check if we have a vector
        else if (naIsVector(val) ) {
          SG_LOG(SG_GENERAL, SG_ALERT, "2nd argument to setprop() is a vector !");
          for (int i=0;i<naVec_size(val);i++) {
          SG_LOG(SG_GENERAL, SG_ALERT, "Updating property via vector index:" << i);
          //TODO: recall and adapted version of findnode() here

          }
        } // vectorized
        
        else {
            // it is neither a string, nor a value, so it bails out here:
            if(!naIsNum(val))
                naRuntimeError(c, "setprop() value is not string or number");
                
            if (SGMisc<double>::isNaN(val.num)) {
                naRuntimeError(c, "setprop() passed a NaN");
            }
            // finally, treat the whole thing a s a number and update that
            result = p->setDoubleValue(val.num);
        }
    } catch (const string& err) {
        naRuntimeError(c, (char *)err.c_str());
    }
    // return the number to the caller
    return naNum(result);
}


Thus, to fix up setprop() to also work on a vector of properties, we need to validate its arguments - by requiring the first argument to be a string (and a valid property path) and the 2nd argument should be a vector.

To do this, we can use the APIs discussed at Howto:Extend_Nasal#Argument_processing

References

References
  1. Thorsten  (Dec 30th, 2016).  Fast updates of plots .
  2. Hooray  (Dec 30th, 2016).  Re: Fast updates of plots .