1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389
|
/*=========================================================================
Program: Visualization Toolkit
Module: vtkPipelineSize.cxx
Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
All rights reserved.
See Copyright.txt or http://www.kitware.com/Copyright.htm 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 notice for more information.
=========================================================================*/
#include "vtkPipelineSize.h"
#include "vtkAlgorithmOutput.h"
#include "vtkConeSource.h"
#include "vtkDataObject.h"
#include "vtkDataReader.h"
#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkLargeInteger.h"
#include "vtkObjectFactory.h"
#include "vtkPSphereSource.h"
#include "vtkPlaneSource.h"
#include "vtkPolyData.h"
#include "vtkPolyDataMapper.h"
#include "vtkDataSetAttributes.h"
#include "vtkStreamingDemandDrivenPipeline.h"
vtkStandardNewMacro(vtkPipelineSize);
// Returns size in kibibytes (1024 bytes)
unsigned long
vtkPipelineSize::GetEstimatedSize(vtkAlgorithm *input, int inputPort,
int connection)
{
unsigned long sizes[3];
unsigned long memorySize = 0;
if(vtkAlgorithmOutput* inInfo =
input->GetInputConnection(inputPort, connection))
{
if (vtkAlgorithm* srcAlg =
vtkAlgorithm::SafeDownCast(
inInfo->GetProducer()))
{
this->ComputeSourcePipelineSize(srcAlg, inInfo->GetIndex(), sizes );
memorySize = sizes[2];
}
}
return memorySize;
}
// The first size is the memory going downstream from here - which is all
// the memory coming in minus any data realeased. The second size is the
// size of the specified output (which can be used by the downstream
// filter when determining how much data it might release). The final size
// is the maximum pipeline size encountered here and upstream from here.
// All sizes are in kibibytes (1024 bytes).
void vtkPipelineSize::ComputeSourcePipelineSize(vtkAlgorithm *src,
int outputPort,
unsigned long size[3])
{
// watch for special sources
// handle vtkDataReader subclasses
if (src->IsA("vtkDataReader"))
{
ifstream *ifs;
vtkDataReader *rdr = vtkDataReader::SafeDownCast(src);
#ifdef _WIN32
ifs = new ifstream(rdr->GetFileName(), ios::in | ios::binary);
#else
ifs = new ifstream(rdr->GetFileName(), ios::in);
#endif
if (!ifs->fail())
{
ifs->seekg(0,ios::end);
int sz = ifs->tellg()/1024;
size[0] = sz;
size[1] = sz;
size[2] = sz;
return;
}
delete ifs;
}
// handle some simple sources
vtkLargeInteger sz;
if (src->IsA("vtkConeSource"))
{
vtkConeSource *s = vtkConeSource::SafeDownCast(src);
sz = s->GetResolution();
sz = sz * 32/1024;
size[0] = sz.CastToUnsignedLong();
size[1] = size[0];
size[2] = size[0];
return;
}
if (src->IsA("vtkPlaneSource"))
{
vtkPlaneSource *s = vtkPlaneSource::SafeDownCast(src);
sz = s->GetXResolution();
sz = sz * s->GetYResolution()*32/1024;
size[0] = sz.CastToUnsignedLong();
size[1] = size[0];
size[2] = size[0];
return;
}
if (src->IsA("vtkPSphereSource"))
{
vtkPSphereSource *s = vtkPSphereSource::SafeDownCast(src);
size[0] = s->GetEstimatedMemorySize();
size[1] = size[0];
size[2] = size[0];
return;
}
// otherwise use generic approach
this->GenericComputeSourcePipelineSize(src,outputPort,size);
}
void vtkPipelineSize::GenericComputeSourcePipelineSize(vtkAlgorithm *src,
int outputPort,
unsigned long size[3])
{
unsigned long outputSize[2];
unsigned long inputPipelineSize[3];
vtkLargeInteger mySize = 0;
unsigned long maxSize = 0;
vtkLargeInteger goingDownstreamSize = 0;
unsigned long *inputSize = NULL;
int idx;
// We need some space to store the input sizes if there are any inputs
int numberOfInputs = src->GetTotalNumberOfInputConnections();
if ( numberOfInputs > 0 )
{
inputSize = new unsigned long[numberOfInputs];
}
// Get the pipeline size propagated down each input. Keep track of max
// pipeline size, how much memory will be required downstream from here,
// the size of each input, and the memory required by this filter when
// it executes.
int port = 0;
int conn = 0;
for (idx = 0; idx < numberOfInputs; ++idx)
{
src->ConvertTotalInputToPortConnection(idx,port,conn);
inputSize[idx] = 0;
if(vtkAlgorithmOutput* inInfo = src->GetInputConnection(port, conn))
{
if (vtkAlgorithm* srcAlg =
vtkAlgorithm::SafeDownCast(inInfo->GetProducer()))
{
// Get the upstream size of the pipeline, the estimated size of this
// input, and the maximum size seen upstream from here.
this->ComputeSourcePipelineSize(srcAlg, inInfo->GetIndex(),
inputPipelineSize);
// Save this input size to possibly be used when estimating output size
inputSize[idx] = inputPipelineSize[1];
// Is the max returned bigger than the max we've seen so far?
if ( inputPipelineSize[2] > maxSize )
{
maxSize = inputPipelineSize[2];
}
// If we are going to release this input, then its size won't matter
// downstream from here.
vtkDemandDrivenPipeline *ddp =
vtkDemandDrivenPipeline::SafeDownCast(srcAlg->GetExecutive());
if (ddp &&
ddp->GetOutputInformation(inInfo->GetIndex())
->Get(vtkDemandDrivenPipeline::RELEASE_DATA()))
{
goingDownstreamSize = goingDownstreamSize + inputPipelineSize[0] -
inputPipelineSize[1];
}
else
{
goingDownstreamSize = goingDownstreamSize + inputPipelineSize[0];
}
// During execution this filter will need all the input data
mySize += inputPipelineSize[0];
}
}
}
// Now the we know the size of all input, compute the output size
this->ComputeOutputMemorySize(src, outputPort, inputSize, outputSize );
// This filter will produce all output so it needs all that memory.
// Also, all this data will flow downstream to the next source (if it is
// the requested output) or will still exist with no chance of being
// released (if it is the non-requested output)
mySize += outputSize[1];
goingDownstreamSize += outputSize[1];
// Is the state of the pipeline during this filter's execution the
// largest that it has been so far?
if ( mySize.CastToUnsignedLong() > maxSize )
{
maxSize = mySize.CastToUnsignedLong();
}
// The first size is the memory going downstream from here - which is all
// the memory coming in minus any data realeased. The second size is the
// size of the specified output (which can be used by the downstream
// filter when determining how much data it might release). The final size
// is the maximum pipeline size encountered here and upstream from here.
size[0] = goingDownstreamSize.CastToUnsignedLong();
size[1] = outputSize[0];
size[2] = maxSize;
// Delete the space we may have created
delete [] inputSize;
}
void vtkPipelineSize::
ComputeOutputMemorySize( vtkAlgorithm *src, int outputPort,
unsigned long *inputSize, unsigned long size[2] )
{
vtkLargeInteger sz;
// watch for special filters such as Glyph3D
if (src->IsA("vtkGlyph3D"))
{
// the output size is the same as the source size * the number of points
// we guess the number of points to be 1/16 of the input size in bytes
if (src->GetTotalNumberOfInputConnections() >= 2)
{
sz = inputSize[1];
sz = sz * inputSize[0]*1024/16;
size[0] = sz.CastToUnsignedLong();
size[1] = size[0];
return;
}
}
this->GenericComputeOutputMemorySize(src, outputPort, inputSize, size);
}
void vtkPipelineSize::
GenericComputeOutputMemorySize( vtkAlgorithm *src, int outputPort,
unsigned long * vtkNotUsed( inputSize ),
unsigned long size[2] )
{
int idx;
vtkLargeInteger tmp = 0;
vtkLargeInteger sz = 0;
vtkDemandDrivenPipeline *ddp =
vtkDemandDrivenPipeline::SafeDownCast(src->GetExecutive());
size[0] = 0;
size[1] = 0;
// loop through all the outputs asking them how big they are given the
// information that they have on their update extent. Keep track of
// the size of the specified output in size[0], and the sum of all
// output size in size[1]. Ignore input sizes in this default implementation.
for (idx = 0; idx < src->GetNumberOfOutputPorts(); ++idx)
{
vtkInformation *outInfo = ddp->GetOutputInformation(idx);
if (outInfo)
{
tmp = 0;
vtkInformation *dataInfo =
outInfo->Get(vtkDataObject::DATA_OBJECT())->GetInformation();
if (dataInfo->Get(vtkDataObject::DATA_EXTENT_TYPE()) ==
VTK_PIECES_EXTENT)
{
// TODO: need something here
tmp = 1;
}
if (dataInfo->Get(vtkDataObject::DATA_EXTENT_TYPE()) == VTK_3D_EXTENT)
{
int uExt[6];
outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_EXTENT(),uExt);
tmp = 4;
vtkInformation *scalarInfo = vtkDataObject::GetActiveFieldInformation(outInfo,
vtkDataObject::FIELD_ASSOCIATION_POINTS, vtkDataSetAttributes::SCALARS);
int numComp = 1;
if (scalarInfo)
{
tmp = vtkDataArray::GetDataTypeSize(
scalarInfo->Get(vtkDataObject::FIELD_ARRAY_TYPE()));
if (scalarInfo->Has(vtkDataObject::FIELD_NUMBER_OF_COMPONENTS()))
{
numComp = scalarInfo->Get(vtkDataObject::FIELD_NUMBER_OF_COMPONENTS());
}
}
tmp *= numComp;
for (idx = 0; idx < 3; ++idx)
{
tmp = tmp*(uExt[idx*2+1] - uExt[idx*2] + 1);
}
tmp /= 1024;
}
if (idx == outputPort )
{
size[0] = tmp.CastToUnsignedLong();
}
}
sz += tmp;
}
size[1] = sz.CastToUnsignedLong();
}
unsigned long vtkPipelineSize::GetNumberOfSubPieces(unsigned long memoryLimit,
vtkPolyDataMapper *mapper)
{
// find the right number of pieces
if (!mapper->GetInput())
{
return 1;
}
unsigned long subDivisions = 1;
unsigned long numPieces = mapper->GetNumberOfPieces();
unsigned long piece = mapper->GetPiece();
unsigned long oldSize, size = 0;
float ratio;
// watch for the limiting case where the size is the maximum size
// represented by an unsigned long. In that case we do not want to do the
// ratio test. We actual test for size < 0.5 of the max unsigned long which
// would indicate that oldSize is about at max unsigned long.
unsigned long maxSize;
maxSize = (((unsigned long)0x1) << (8*sizeof(unsigned long) - 1));
// we also have to watch how many pieces we are creating. Since
// NumberOfStreamDivisions is an int, it cannot be more that say 2^31
// (which is a bit much anyhow) so we also stop if the number of pieces is
// too large. Here we start off with the current number of pieces.
int count = (int) (log(static_cast<float>(numPieces))/log(static_cast<float>(2)));
// double the number of pieces until the size fits in memory
// or the reduction in size falls to 20%
do
{
oldSize = size;
vtkInformation* inInfo = mapper->GetInputInformation();
inInfo->Set(vtkStreamingDemandDrivenPipeline::UPDATE_PIECE_NUMBER(),
piece*subDivisions);
inInfo->Set(vtkStreamingDemandDrivenPipeline::UPDATE_NUMBER_OF_PIECES(),
numPieces*subDivisions);
inInfo->Set(vtkStreamingDemandDrivenPipeline::UPDATE_NUMBER_OF_GHOST_LEVELS(),
0);
mapper->GetInputAlgorithm()->PropagateUpdateExtent();
size = this->GetEstimatedSize(mapper,0,0);
// watch for the first time through
if (!oldSize)
{
ratio = 0.5;
}
// otherwise the normal ratio calculation
else
{
ratio = size/(float)oldSize;
}
subDivisions = subDivisions*2;
count++;
}
while (size > memoryLimit &&
(size > maxSize || ratio < 0.8) && count < 29);
// undo the last *2
subDivisions = subDivisions/2;
return subDivisions;
}
void vtkPipelineSize::PrintSelf(ostream& os, vtkIndent indent)
{
this->Superclass::PrintSelf(os, indent);
}
|