AvtAccessor

Using VTK's Get/SetTuple methods on a vtkDataArray are much slower than accessing the raw data in the data arrays. This is caused by virtual function overhead and data type conversions. Using these methods is convenient because you can write code that modifies the data even though it might be stored in the array as many different types.

Fast path

For performance critical parts of the code, we often find ourselves doing things like this:

void
DoSomething(vtkDataArray *array)
{
    if(array->GetType() == VTK_FLOAT)
    {
        // FAST PATH
        float *ptr = (float *)array->GetVoidPointer(0);
        for(int i = 0; i < array->GetNumberOfTuples(); ++i)
        {
           // Do something complex with ptr[i]
        }
    }
    else
    {
        // The same code using Get/SetTuple.
    }
}

Fast path with templates

While adding this fast path can provide nice speedup, it's more code to write. If you also want a fast path for other datatypes (think float and double fast paths) then you must write another case and duplicate code. Of course, you can always modify your code bodies to be templated:

template <typename T>
void DoDomethingKernel(T *ptr, int ntuples)
{
    for(int i = 0; i < nt; ++i)
    {
        // Do something complex with ptr[i]
    }
}

void
DoSomething(vtkDataArray *array)
{
    int nt = array->GetNumberOfTuples();
    if(array->GetType() == VTK_FLOAT)
        DoSomethingKernel((float *)array->GetVoidPointer(0), nt);
    else if(array->GetType() == VTK_DOUBLE)
        DoSomethingKernel((double *)array->GetVoidPointer(0), nt);
    else
    {
        // The same code using Get/SetTuple.
    }
}

Fast path with accessors

Using the template version of the raw array access code can significantly cut down on the amount of code that you have to write. That's a definite plus. However, you still may need to maintain a Get/SetTuple version of the code for other datatypes otherwise you better add template cases for every data type you might encounter (int,short,long,char,...) which can bloat your code and provide fast paths for data types you may rarely encounter.

It is possible to use avtAccessor to access the vtkDataArray using a style of method accesses similar to what you would use for vtkDataArray. An accessor is kind of like an iterator for vtkDataArray but it also provides methods that vtkDataArray has for accessing tuples and components.

There are 2 classes of "accessors": Direct and Tuple. The avtDirectAccessor class knows the underlying type of the data and does array-style accessing of elements. The avtTupleAccessor access class uses the "safe" Get/SetTuple methods on the vtkDataArray.

Acessors have some nice properties:

  • The accessor classes provide a very similar interface to vtkDataArray, which makes adapting code to use accessors easy.
  • You can write the SAME template method body and access the data either in a fast raw method or by using Get/SetTuple
  • With avtDirectAccessor, you can get the data in the native format directly with no intermediate conversion through double as required by vtkDataArray.
template <typename Accessor>
void DoDomethingKernel(vtkDataArray *array_real)
{
    Accessor array(array_real);
    for(int i = 0; i < array.GetNumberOfTuples(); ++i)
    {
        // Do something complex with array.GetTuple1(i)
    }
}

void
DoSomething(vtkDataArray *array)
{
    if(array->GetType() == VTK_FLOAT)
        DoSomethingKernel<avtDirectAccessor<float> >(array);
    else if(array->GetType() == VTK_DOUBLE)
        DoSomethingKernel<avtDirectAccessor<double> >(array);
    else
        DoSomethingKernel<avtTupleAccessor>(array);
}

If the DoSomethingKernel and the previous implementation of the Get/SetTuple backup case were both large, you save a lot of code by only using the DoSomethingKernel template using accessors. It's more maintainable too since there's one high performance implementation instead of several and it looks a lot like the original version of the function.

Performance

Accessors are inlined which eliminates any additional function overhead. Using avtTupleAccessor does not impact performance either way. In the case of the direct accessor, calls to Get/SetTuple are as efficient as accessing the arrays directly.

Compared to the original vtkDataArray Get/SetTuple method, accessors can save up to 30% of function execution time just in calls to virtual functions.

It's possible to increase the performance of accessors even further if you restructure your loops a little in the code that iterates over tuples. Much of the speed increase is realized by replacing costly index calculations in vtkDataArray with pointer arithmetic in the direct accessor.

template <typename Accessor>
void DoDomethingKernel(vtkDataArray *array_real)
{
    Accessor array(array_real);
    array.InitTraversal();
    while(array.Iterating())
    {
        // Do something complex with this tuple: array.GetTuple1()

        // Go to the next tuple
        array++;
    }
}