In our application we have implemented a wrapper class using the vtkGenericDataArray<DerivedType, T> class. Our class is called CV::Array. Generally things are working fine but as I start to profile our code to see what is taking so long for some operations (Volume rendering is my current rabbit hole) I am seeing a pattern which is the call to vtkDataArray::GetFiniteRange(int). That will then cause the chain of “ComputeFiniteRange()” to get hit. Thing is, we already have computed those values and cached them in the CV::Array instance. I have been looking for something to override from vtkGenericDataArray<> in order to use the already cached values but I feel like I am just missing something, hopefully obvious.
I’ve been trying to dig into the VTK sources to try and figure out what we missed when we implemented CV::Array but I’m coming up empty.
For example here is one stack trace from my MacOS Machine:
4.40 s 100.0% 0 s vtkVolumeTexture::SelectTextureFormat(unsigned int&, unsigned int&, int&, int, int)
4.40 s 100.0% 0 s vtkDataArray::GetFiniteRange(int)
4.40 s 100.0% 0 s vtkDataArray::GetFiniteRange(double*, int)
4.40 s 100.0% 0 s vtkDataArray::ComputeFiniteRange(double*, int)
4.40 s 100.0% 0 s vtkDataArray::ComputeFiniteRange(double*, int, unsigned char const*, unsigned char)
4.40 s 100.0% 0 s vtkDataArray::ComputeFiniteScalarRange(double*)
4.40 s 100.0% 0 s vtkDataArray::ComputeFiniteScalarRange(double*, unsigned char const*, unsigned char)
4.40 s 100.0% 0 s void (anonymous namespace)::FiniteScalarRangeDispatchWrapper::operator()<vtkDataArray>(vtkDataArray*)
4.40 s 100.0% 0 s bool vtkDataArrayPrivate::DoComputeScalarRange<vtkDataArray, double, vtkDataArrayPrivate::FiniteValues>(vtkDataArray*, double*, vtkDataArrayPrivate::FiniteValues, unsigned char const*, unsigned char)
4.40 s 100.0% 0 s bool vtkDataArrayPrivate::ComputeScalarRange<1>::operator()<vtkDataArray, double>(vtkDataArray*, double*, vtkDataArrayPrivate::FiniteValues, unsigned char const*, unsigned char)
4.40 s 100.0% 0 s void vtkSMPTools::For<vtkDataArrayPrivate::FiniteMinAndMax<1, vtkDataArray, double>>(long long, long long, vtkDataArrayPrivate::FiniteMinAndMax<1, vtkDataArray, double>&)
4.40 s 100.0% 0 s void vtkSMPTools::For<vtkDataArrayPrivate::FiniteMinAndMax<1, vtkDataArray, double>>(long long, long long, long long, vtkDataArrayPrivate::FiniteMinAndMax<1, vtkDataArray, double>&)
4.40 s 100.0% 0 s vtk::detail::smp::vtkSMPTools_FunctorInternal<vtkDataArrayPrivate::FiniteMinAndMax<1, vtkDataArray, double>, true>::For(long long, long long, long long)
4.40 s 100.0% 0 s void vtk::detail::smp::vtkSMPToolsAPI::For<vtk::detail::smp::vtkSMPTools_FunctorInternal<vtkDataArrayPrivate::FiniteMinAndMax<1, vtkDataArray, double>, true>>(long long, long long, long long, vtk::detail::smp::vtkSMPTools_FunctorInternal<vtkDataArrayPrivate::FiniteMinAndMax<1, vtkDataArray, double>, true>&)
4.40 s 100.0% 0 s void vtk::detail::smp::vtkSMPToolsImpl<(vtk::detail::smp::BackendType)2>::For<vtk::detail::smp::vtkSMPTools_FunctorInternal<vtkDataArrayPrivate::FiniteMinAndMax<1, vtkDataArray, double>, true>>(long long, long long, long long, vtk::detail::smp::vtkSMPTools_FunctorInternal<vtkDataArrayPrivate::FiniteMinAndMax<1, vtkDataArray, double>, true>&)
4.40 s 100.0% 0 s vtk::detail::smp::vtkSMPToolsImplForTBB(long long, long long, long long, void (*)(void*, long long, long long, long long), void*)
4.40 s 100.0% 0 s void vtk::detail::smp::ExecuteFunctorTBB<vtk::detail::smp::vtkSMPTools_FunctorInternal<vtkDataArrayPrivate::FiniteMinAndMax<1, vtkDataArray, double>, true>>(void*, long long, long long, long long)
4.40 s 100.0% 0 s void tbb::detail::d1::parallel_for<tbb::detail::d1::blocked_range<long long>, vtk::detail::smp::FuncCall<vtk::detail::smp::vtkSMPTools_FunctorInternal<vtkDataArrayPrivate::FiniteMinAndMax<1, vtkDataArray, double>, true>>>(tbb::detail::d1::blocked_range<long long> const&, vtk::detail::smp::FuncCall<vtk::detail::smp::vtkSMPTools_FunctorInternal<vtkDataArrayPrivate::FiniteMinAndMax<1, vtkDataArray, double>, true>> const&)
4.40 s 100.0% 0 s tbb::detail::d1::start_for<tbb::detail::d1::blocked_range<long long>, vtk::detail::smp::FuncCall<vtk::detail::smp::vtkSMPTools_FunctorInternal<vtkDataArrayPrivate::FiniteMinAndMax<1, vtkDataArray, double>, true>>, tbb::detail::d1::auto_partitioner const>::run(tbb::detail::d1::blocked_range<long long> const&, vtk::detail::smp::FuncCall<vtk::detail::smp::vtkSMPTools_FunctorInternal<vtkDataArrayPrivate::FiniteMinAndMax<1, vtkDataArray, double>, true>> const&, tbb::detail::d1::auto_partitioner const&)
4.40 s 100.0% 0 s tbb::detail::d1::start_for<tbb::detail::d1::blocked_range<long long>, vtk::detail::smp::FuncCall<vtk::detail::smp::vtkSMPTools_FunctorInternal<vtkDataArrayPrivate::FiniteMinAndMax<1, vtkDataArray, double>, true>>, tbb::detail::d1::auto_partitioner const>::run(tbb::detail::d1::blocked_range<long long> const&, vtk::detail::smp::FuncCall<vtk::detail::smp::vtkSMPTools_FunctorInternal<vtkDataArrayPrivate::FiniteMinAndMax<1, vtkDataArray, double>, true>> const&, tbb::detail::d1::auto_partitioner const&, tbb::detail::d1::task_group_context&)
4.40 s 100.0% 0 s tbb::detail::d1::execute_and_wait(tbb::detail::d1::task&, tbb::detail::d1::task_group_context&, tbb::detail::d1::wait_context&, tbb::detail::d1::task_group_context&)
4.40 s 100.0% 0 s tbb::detail::r1::execute_and_wait(tbb::detail::d1::task&, tbb::detail::d1::task_group_context&, tbb::detail::d1::wait_context&, tbb::detail::d1::task_group_context&)
4.40 s 100.0% 0 s tbb::detail::r1::task_dispatcher::execute_and_wait(tbb::detail::d1::task*, tbb::detail::d1::wait_context&, tbb::detail::d1::task_group_context&)
4.40 s 100.0% 0 s tbb::detail::d1::task* tbb::detail::r1::task_dispatcher::local_wait_for_all<tbb::detail::r1::external_waiter>(tbb::detail::d1::task*, tbb::detail::r1::external_waiter&)
4.40 s 100.0% 0 s tbb::detail::d1::task* tbb::detail::r1::task_dispatcher::local_wait_for_all<false, tbb::detail::r1::external_waiter>(tbb::detail::d1::task*, tbb::detail::r1::external_waiter&)
4.40 s 100.0% 0 s tbb::detail::d1::start_for<tbb::detail::d1::blocked_range<long long>, vtk::detail::smp::FuncCall<vtk::detail::smp::vtkSMPTools_FunctorInternal<vtkDataArrayPrivate::FiniteMinAndMax<1, vtkDataArray, double>, true>>, tbb::detail::d1::auto_partitioner const>::execute(tbb::detail::d1::execution_data&)
4.40 s 100.0% 0 s void tbb::detail::d1::partition_type_base<tbb::detail::d1::auto_partition_type>::execute<tbb::detail::d1::start_for<tbb::detail::d1::blocked_range<long long>, vtk::detail::smp::FuncCall<vtk::detail::smp::vtkSMPTools_FunctorInternal<vtkDataArrayPrivate::FiniteMinAndMax<1, vtkDataArray, double>, true>>, tbb::detail::d1::auto_partitioner const>, tbb::detail::d1::blocked_range<long long>>(tbb::detail::d1::start_for<tbb::detail::d1::blocked_range<long long>, vtk::detail::smp::FuncCall<vtk::detail::smp::vtkSMPTools_FunctorInternal<vtkDataArrayPrivate::FiniteMinAndMax<1, vtkDataArray, double>, true>>, tbb::detail::d1::auto_partitioner const>&, tbb::detail::d1::blocked_range<long long>&, tbb::detail::d1::execution_data&)
4.40 s 100.0% 0 s void tbb::detail::d1::dynamic_grainsize_mode<tbb::detail::d1::adaptive_mode<tbb::detail::d1::auto_partition_type>>::work_balance<tbb::detail::d1::start_for<tbb::detail::d1::blocked_range<long long>, vtk::detail::smp::FuncCall<vtk::detail::smp::vtkSMPTools_FunctorInternal<vtkDataArrayPrivate::FiniteMinAndMax<1, vtkDataArray, double>, true>>, tbb::detail::d1::auto_partitioner const>, tbb::detail::d1::blocked_range<long long>>(tbb::detail::d1::start_for<tbb::detail::d1::blocked_range<long long>, vtk::detail::smp::FuncCall<vtk::detail::smp::vtkSMPTools_FunctorInternal<vtkDataArrayPrivate::FiniteMinAndMax<1, vtkDataArray, double>, true>>, tbb::detail::d1::auto_partitioner const>&, tbb::detail::d1::blocked_range<long long>&, tbb::detail::d1::execution_data&)
4.40 s 100.0% 0 s tbb::detail::d1::start_for<tbb::detail::d1::blocked_range<long long>, vtk::detail::smp::FuncCall<vtk::detail::smp::vtkSMPTools_FunctorInternal<vtkDataArrayPrivate::FiniteMinAndMax<1, vtkDataArray, double>, true>>, tbb::detail::d1::auto_partitioner const>::run_body(tbb::detail::d1::blocked_range<long long>&)
4.40 s 100.0% 0 s vtk::detail::smp::FuncCall<vtk::detail::smp::vtkSMPTools_FunctorInternal<vtkDataArrayPrivate::FiniteMinAndMax<1, vtkDataArray, double>, true>>::operator()(tbb::detail::d1::blocked_range<long long> const&) const
4.40 s 100.0% 0 s vtk::detail::smp::vtkSMPTools_FunctorInternal<vtkDataArrayPrivate::FiniteMinAndMax<1, vtkDataArray, double>, true>::Execute(long long, long long)
4.40 s 100.0% 329.00 ms vtkDataArrayPrivate::FiniteMinAndMax<1, vtkDataArray, double>::operator()(long long, long long)
I know the volume data that I am loading should be one of our CV::Arrays and the range should have already been computed. Maybe I’m just wrong and the input CV::Array has morphed into a vtkDataArray? Dunno. I feel lost so any help would be greatly appreciated.
I have implemented void GetFiniteValueRange(T* range, int compIdx) in CV::Array. The superclass’s version is not virtual so I’m sure I should be trying that.
Thank You.