diff --git a/Code/Common/otbPipelineMemoryPrintCalculator.h b/Code/Common/otbPipelineMemoryPrintCalculator.h new file mode 100644 index 0000000000000000000000000000000000000000..02498966e87d9ecd94d5f9d94d28aece4f2ca51b --- /dev/null +++ b/Code/Common/otbPipelineMemoryPrintCalculator.h @@ -0,0 +1,223 @@ +/*========================================================================= + + Program: ORFEO Toolbox + Language: C++ + Date: $Date$ + Version: $Revision$ + + + Copyright (c) Centre National d'Etudes Spatiales. All rights reserved. + See OTBCopyright.txt for details. + + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +#ifndef __otbPipelineMemoryPrintCalculator_h +#define __otbPipelineMemoryPrintCalculator_h + +#include "itkProcessObject.h" +#include "itkDataObject.h" +#include "otbMath.h" +#include "itkImage.h" +#include "itkVectorImage.h" +#include "itkFixedArray.h" + +namespace otb +{ +/** \class PipelineMemoryPrintCalculator + * + */ +class ITK_EXPORT PipelineMemoryPrintCalculator : + public itk::Object +{ +public: + /** Standard class typedefs */ + typedef PipelineMemoryPrintCalculator Self; + typedef itk::Object Superclass; + typedef itk::SmartPointer<Self> Pointer; + typedef itk::SmartPointer<const Self> ConstPointer; + + /** Useful typedefs */ + typedef itk::ProcessObject ProcessObjectType; + typedef ProcessObjectType::Pointer ProcessObjectPointerType; + typedef itk::DataObject DataObjectType; + typedef DataObjectType::Pointer DataObjectPointerType; + + /** Run-time type information (and related methods). */ + itkTypeMacro(PipelineMemoryPrintCalculator, itk::Object); + + /** Method for creation through the object factory. */ + itkNewMacro(Self); + + /** Get the total memory print (in Mo) */ + itkGetMacro(MemoryPrint,double); + + /** Set/Get the available memory for pipeline execution (in Mo) */ + itkSetMacro(AvailableMemory,double); + itkGetMacro(AvailableMemory,double); + + /** Get the optimal number of stream division */ + itkGetMacro(OptimalNumberOfStreamDivisions,unsigned long); + + /** Set last pipeline filter */ + itkSetObjectMacro(DataToWrite,DataObjectType); + + /** Compute pipeline memory print */ + void Compute() + { + // Dry run of pipeline synchronisation + m_DataToWrite->UpdateOutputInformation(); + m_DataToWrite->SetRequestedRegionToLargestPossibleRegion(); + m_DataToWrite->PropagateRequestedRegion(); + + // Get the source process object + ProcessObjectType * source = m_DataToWrite->GetSource(); + + // Check if source exists + if(source) + { + // Call the recursive memory print evaluation + m_MemoryPrint = EvaluateMemoryPrint(source); + } + else + { + // Get memory print for this data only + std::cout<<"DataToWrite has no source."<<std::endl; + m_MemoryPrint = EvaluateDataObjectPrint(m_DataToWrite); + } + + // TODO: Remove this ! + m_MemoryPrint*=2; + + // Compute the optimal number of stream division + m_OptimalNumberOfStreamDivisions = vcl_ceil(m_MemoryPrint + /m_AvailableMemory); + } + +protected: + /** Constructor */ + PipelineMemoryPrintCalculator() + : m_MemoryPrint(0), + m_AvailableMemory(256), + m_OptimalNumberOfStreamDivisions(0), + m_DataToWrite(NULL) + {} + + /** Destructor */ + virtual ~PipelineMemoryPrintCalculator() {} + + /** PrintSelf method */ + void PrintSelf(std::ostream& os, itk::Indent indent) const + { + // Call superclass implementation + Superclass::PrintSelf(os,indent); + } + + /** Internal recursive method to evaluate memory print in bytes */ + double EvaluateMemoryPrint(ProcessObjectType * process) + { + // This variable will store the final print + double print = 0; + + // Retrieve the array of inputs + ProcessObjectType::DataObjectPointerArray inputs = process->GetInputs(); + // First, recurse on each input source + for(unsigned int i =0; i < process->GetNumberOfInputs();++i) + { + // Retrieve the data object + DataObjectType * input = inputs[i]; + + // Retrieve possible source + ProcessObjectType * source = input->GetSource(); + + // If data object has a source + if(source) + { + print += this->EvaluateMemoryPrint(source); + } + else + { + double localPrint = this->EvaluateDataObjectPrint(input); + std::cout<<process->GetNameOfClass()<<"::Input"<<i<<" (sourceless) "<<localPrint<<" Mo"<<std::endl; + print += localPrint; + } + } + // Retrieve the output array + ProcessObjectType::DataObjectPointerArray outputs = process->GetOutputs(); + + // Now, evaluate the current object print + for(unsigned int i =0; i < process->GetNumberOfOutputs();++i) + { + double localPrint = this->EvaluateDataObjectPrint(outputs[0]); + std::cout<<process->GetNameOfClass()<<"::Output"<<i<<" "<<localPrint<<" Mo"<<std::endl; + print += localPrint; + } + + // Finally, return the total print + return print; + } + + /** Internal method to evaluate the print (in Mo) of a single data object */ + double EvaluateDataObjectPrint(DataObjectType * data) + { + +#define OTB_IMAGE_SIZE_BLOCK(type) \ + if(dynamic_cast<itk::Image<type,2> *>(data) != NULL) \ + { \ + itk::Image<type,2> * image = dynamic_cast<itk::Image<type,2> *>(data);\ + std::cout<<"Image of "<< image->GetRequestedRegion().GetNumberOfPixels() <<" pixels of type " # type ": "<<sizeof(type)<<" octets, ("<<image->GetRequestedRegion()<<")"<<std::endl; \ + return image->GetRequestedRegion().GetNumberOfPixels() * image->GetNumberOfComponentsPerPixel() * sizeof(type) * OctetToMegaOctet; \ + } \ + if(dynamic_cast<itk::VectorImage<type,2> * >(data) != NULL) \ + { \ + itk::VectorImage<type,2> * image = dynamic_cast<itk::VectorImage<type,2> *>(data);\ + std::cout<<"VectorImage of "<< image->GetRequestedRegion().GetNumberOfPixels() <<" pixels of "<<image->GetNumberOfComponentsPerPixel()<<" components of type " # type ": "<<sizeof(type)<<" octets, ("<<image->GetRequestedRegion()<<")"<<std::endl;\ + return image->GetRequestedRegion().GetNumberOfPixels() * image->GetNumberOfComponentsPerPixel() * sizeof(type) * OctetToMegaOctet; \ + } \ + + + OTB_IMAGE_SIZE_BLOCK(unsigned char) + OTB_IMAGE_SIZE_BLOCK(char) + OTB_IMAGE_SIZE_BLOCK(unsigned short) + OTB_IMAGE_SIZE_BLOCK( short) + OTB_IMAGE_SIZE_BLOCK(unsigned int) + OTB_IMAGE_SIZE_BLOCK( int) + OTB_IMAGE_SIZE_BLOCK(unsigned long) + OTB_IMAGE_SIZE_BLOCK( long) + OTB_IMAGE_SIZE_BLOCK(float) + OTB_IMAGE_SIZE_BLOCK( double) + OTB_IMAGE_SIZE_BLOCK(std::complex<float>) + OTB_IMAGE_SIZE_BLOCK(std::complex<double>) + typedef itk::FixedArray<float,2> FloatFixedArray2Type; + typedef itk::FixedArray<float,2> DoubleFixedArray2Type; + OTB_IMAGE_SIZE_BLOCK(FloatFixedArray2Type) + OTB_IMAGE_SIZE_BLOCK(DoubleFixedArray2Type) + + return 0; + } + +private: + PipelineMemoryPrintCalculator(const Self &); //purposely not implemented + void operator =(const Self&); //purposely not implemented + + /** The total memory print of the pipeline */ + double m_MemoryPrint; + /** The available memory for pipeline execution */ + double m_AvailableMemory; + /** The optimal number of stream division */ + unsigned long m_OptimalNumberOfStreamDivisions; + + /** Pointer to the last pipeline filter */ + DataObjectPointerType m_DataToWrite; + + static const double OctetToMegaOctet; +}; + +const double PipelineMemoryPrintCalculator::OctetToMegaOctet = 1./vcl_pow(2,20); + +} // end of namespace otb + +#endif diff --git a/Testing/Code/Common/CMakeLists.txt b/Testing/Code/Common/CMakeLists.txt index 3154ff08827babd976f2e3c985c231dc9c57c0fb..386040f8ed242b189ed02ce5dc39a9d856419daa 100644 --- a/Testing/Code/Common/CMakeLists.txt +++ b/Testing/Code/Common/CMakeLists.txt @@ -946,8 +946,14 @@ ADD_TEST(coTuVariableLengthVectorConverter ${COMMON_TESTS12} # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ otbCommonTests13 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +ADD_TEST(coTuPipelineMemoryPrintCalculatorNew ${COMMON_TESTS13} + otbPipelineMemoryPrintCalculatorNew + ) - +ADD_TEST(coTvPipelineMemoryPrintCalculator ${COMMON_TESTS13} + otbPipelineMemoryPrintCalculatorTest + ${INPUTDATA}/qb_RoadExtract.img +) # ------- Fichiers sources CXX ----------------------------------- @@ -1106,7 +1112,8 @@ otbVariableLengthVectorConverter.cxx SET(BasicCommon_SRCS13 otbCommonTests13.cxx -) +otbPipelineMemoryPrintCalculatorTest.cxx) + OTB_ADD_EXECUTABLE(otbCommonTests1 "${BasicCommon_SRCS1}" "OTBIO;OTBTesting") OTB_ADD_EXECUTABLE(otbCommonTests2 "${BasicCommon_SRCS2}" "OTBIO;OTBTesting") diff --git a/Testing/Code/Common/otbCommonTests13.cxx b/Testing/Code/Common/otbCommonTests13.cxx index fd1171dd7454d5da1e168c47ffa98b7d99a57892..8da628bf32cbb8990fc3c7c3e8fcf2826ceeb1d7 100644 --- a/Testing/Code/Common/otbCommonTests13.cxx +++ b/Testing/Code/Common/otbCommonTests13.cxx @@ -27,4 +27,6 @@ void RegisterTests() { // REGISTER_TEST(otbGISTableSourceNew); + REGISTER_TEST(otbPipelineMemoryPrintCalculatorNew); + REGISTER_TEST(otbPipelineMemoryPrintCalculatorTest); } diff --git a/Testing/Code/Common/otbPipelineMemoryPrintCalculatorTest.cxx b/Testing/Code/Common/otbPipelineMemoryPrintCalculatorTest.cxx new file mode 100644 index 0000000000000000000000000000000000000000..e52dd61cbe5efd21430b4623ef7ad7b140ef3cf6 --- /dev/null +++ b/Testing/Code/Common/otbPipelineMemoryPrintCalculatorTest.cxx @@ -0,0 +1,56 @@ +/*========================================================================= + + Program: ORFEO Toolbox + Language: C++ + Date: $Date$ + Version: $Revision$ + + + Copyright (c) Centre National d'Etudes Spatiales. All rights reserved. + See OTBCopyright.txt for details. + + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +#include "otbPipelineMemoryPrintCalculator.h" + +#include "otbVectorImage.h" +#include "otbImage.h" +#include "otbImageFileReader.h" +#include "otbVectorImageToIntensityImageFilter.h" + +int otbPipelineMemoryPrintCalculatorNew(int argc, char * argv[]) +{ + otb::PipelineMemoryPrintCalculator::Pointer calculator = otb::PipelineMemoryPrintCalculator::New(); + + return EXIT_SUCCESS; +} + + +int otbPipelineMemoryPrintCalculatorTest(int argc, char * argv[]) +{ + typedef otb::VectorImage<double,2> VectorImageType; + typedef otb::Image<double,2> ImageType; + typedef otb::ImageFileReader<VectorImageType> ReaderType; + typedef otb::VectorImageToIntensityImageFilter + <VectorImageType,ImageType> IntensityImageFilterType; + + ReaderType::Pointer reader = ReaderType::New(); + reader->SetFileName(argv[1]); + + IntensityImageFilterType::Pointer intensity = IntensityImageFilterType::New(); + intensity->SetInput(reader->GetOutput()); + + otb::PipelineMemoryPrintCalculator::Pointer calculator = otb::PipelineMemoryPrintCalculator::New(); + calculator->SetDataToWrite(intensity->GetOutput()); + calculator->SetAvailableMemory(0.1); + calculator->Compute(); + + std::cout<<"Pipeline memory print: "<<calculator->GetMemoryPrint()<<" Mo"<<std::endl; + std::cout<<"Optimal stream division: "<<calculator->GetOptimalNumberOfStreamDivisions()<<" tiles"<<std::endl; + + return EXIT_SUCCESS; +}