Opened 9 years ago
Closed 5 years ago
#5748 closed task (wontfix)
Reduce stack memory usage
Reported by: | Kurt Schwehr | Owned by: | Kurt Schwehr |
---|---|---|---|
Priority: | normal | Milestone: | closed_because_of_github_migration |
Component: | default | Version: | unspecified |
Severity: | normal | Keywords: | |
Cc: |
Description
In multi-threaded programs, stack usage is particularly important. GDAL currently uses large amount of memory on the stack. I plan to gradually work towards reducing this usage. Some strategies:
- Move local variables into the scope they are used
- Allocate large structures on the heap when possible
Change History (8)
comment:1 by , 9 years ago
comment:2 by , 9 years ago
Status: | new → assigned |
---|
Even, Agreed. It's going to take a while to work through this and some it matters more when running with the compiler in debug / no-optimize mode where the compiler can't reorder things. My first patch is coming in a few minutes. I haven't yet started profiling where a lot of the memory usage is coming from.
comment:3 by , 8 years ago
Proposed first patch for reducing large stacks. Because vectors are required to dynamically allocate their storage, that means they must use the heap. The storage is required to be contiguous and pointer to the first element can be used as a C array as long as the size of the vector is not changed. By using the fill constructor, we can start off with the required size and replace the memset.
- http://www.cplusplus.com/reference/vector/vector/vector/
- http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#69
- https://isocpp.org/wiki/faq/containers#vector-is-contiguous
- http://stackoverflow.com/questions/1733143/converting-between-c-stdvector-and-c-array-without-copying
-
frmts/netcdf/netcdfdataset.cpp
a b 35 35 #include "gdal_frmts.h" 36 36 #include "netcdfdataset.h" 37 37 38 #include <map> //for NCDFWriteProjAttribs()39 38 #include <limits> 39 #include <map> //for NCDFWriteProjAttribs() 40 #include <vector> 41 42 using std::vector; 40 43 41 44 CPL_CVSID("$Id: netcdfdataset.cpp 32423 2015-12-21 12:33:17Z rouault $"); 42 45 … … netCDFRasterBand::netCDFRasterBand( netCDFDataset *poNCDFDS, 432 435 /* -------------------------------------------------------------------- */ 433 436 #ifdef NETCDF_HAS_NC4 434 437 int nTmpFormat = 0; 435 size_t chunksize[ MAX_NC_DIMS ]; 438 vector<size_t> chunksizeStorage(MAX_NC_DIMS, 0); 439 size_t * const chunksize = &chunksizeStorage[0]; 440 436 441 status = nc_inq_format( cdfid, &nTmpFormat); 437 442 NetCDFFormatEnum eTmpFormat = static_cast<NetCDFFormatEnum>(nTmpFormat); 438 443 if( ( status == NC_NOERR ) && ( ( eTmpFormat == NCDF_FORMAT_NC4 ) || … … CPLErr netCDFRasterBand::CreateBandMetadata( const int *paDimIds ) 1016 1021 int nDims = 0; 1017 1022 /* status = */ nc_inq_varndims( cdfid, nVarID, &nDims ); 1018 1023 1019 char szMetaTemp[256]; 1024 vector<char> szMetaTempStorage(256, 0); 1025 char * const szMetaTemp = &szMetaTempStorage[0]; 1020 1026 if( nDims == 1 ) { 1021 1027 size_t count[1] = {1}; 1022 1028 size_t start[1] = {static_cast<size_t>(result)}; … … CPLErr netCDFRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff, 1196 1202 /* Locate X, Y and Z position in the array */ 1197 1203 /* -------------------------------------------------------------------- */ 1198 1204 1199 size_t start[ MAX_NC_DIMS ]; 1200 memset( start, 0, sizeof( start ) ); 1205 vector<size_t> startStorage(MAX_NC_DIMS, 0); 1206 size_t * const start = &startStorage[0]; 1207 1201 1208 start[nBandXPos] = nBlockXOff * nBlockXSize; 1202 1209 1203 1210 // check y order … … CPLErr netCDFRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff, 1223 1230 start[nBandYPos] = nBlockYOff * nBlockYSize; 1224 1231 } 1225 1232 1226 size_t edge[ MAX_NC_DIMS ];1227 memset( edge, 0, sizeof( edge ) );1233 vector<size_t> edgeStorage(MAX_NC_DIMS, 0); 1234 size_t * const edge = &edgeStorage[0]; 1228 1235 1229 1236 edge[nBandXPos] = nBlockXSize; 1230 1237 if ( ( start[nBandXPos] + edge[nBandXPos] ) > (size_t)nRasterXSize ) … … CPLErr netCDFRasterBand::IWriteBlock( CPL_UNUSED int nBlockXOff, 1380 1387 /* Locate X, Y and Z position in the array */ 1381 1388 /* -------------------------------------------------------------------- */ 1382 1389 1383 size_t start[ MAX_NC_DIMS];1384 memset( start, 0, sizeof( start ) );1390 vector<size_t> startStorage(MAX_NC_DIMS, 0); 1391 size_t * const start = &startStorage[0]; 1385 1392 1386 1393 start[nBandXPos] = 0; // x dim can move around in array 1387 1394 // check y order … … CPLErr netCDFRasterBand::IWriteBlock( CPL_UNUSED int nBlockXOff, 1391 1398 start[nBandYPos] = nBlockYOff; // y 1392 1399 } 1393 1400 1394 size_t edge[ MAX_NC_DIMS ];1395 memset( edge, 0, sizeof( edge ) );1401 vector<size_t> edgeStorage(MAX_NC_DIMS, 0); 1402 size_t * const edge = &edgeStorage[0]; 1396 1403 1397 edge[nBandXPos] = nBlockXSize; 1404 edge[nBandXPos] = nBlockXSize; 1398 1405 edge[nBandYPos] = 1; 1399 1406 1400 1407 if( nd == 3 ) { … … double netCDFDataset::FetchCopyParm( const char *pszGridMappingValue, 1701 1708 const char *pszParm, double dfDefault ) 1702 1709 1703 1710 { 1704 char szTemp[ 256 ]; 1705 snprintf(szTemp, sizeof(szTemp), "%s#%s", pszGridMappingValue, pszParm); 1711 const int szTempSize = 256; 1712 vector<char> szTempStorage(szTempSize, 0); 1713 char * const szTemp = &szTempStorage[0]; 1714 1715 snprintf(szTemp, szTempSize, "%s#%s", pszGridMappingValue, pszParm); 1706 1716 const char *pszValue = CSLFetchNameValue(papszMetadata, szTemp); 1707 1717 1708 1718 if( pszValue ) … … double netCDFDataset::FetchCopyParm( const char *pszGridMappingValue, 1719 1729 1720 1730 char** netCDFDataset::FetchStandardParallels( const char *pszGridMappingValue ) 1721 1731 { 1722 char szTemp[256 ]; 1723 //cf-1.0 tags 1724 snprintf(szTemp, sizeof(szTemp), "%s#%s", pszGridMappingValue, CF_PP_STD_PARALLEL); 1732 const int szTempSize = 256; 1733 vector<char> szTempStorage(szTempSize, 0); 1734 char * const szTemp = &szTempStorage[0]; 1735 1736 // cf-1.0 tags 1737 snprintf( szTemp, szTempSize, "%s#%s", pszGridMappingValue, 1738 CF_PP_STD_PARALLEL); 1725 1739 const char *pszValue = CSLFetchNameValue( papszMetadata, szTemp ); 1726 1740 1727 1741 char **papszValues = NULL; … … int netCDFDataset::DefVarDeflate( 5757 5771 if ( eCompress == NCDF_COMPRESS_DEFLATE ) { 5758 5772 // Must set chunk size to avoid huge performance hit (set bChunkingArg=TRUE) 5759 5773 // perhaps another solution it to change the chunk cache? 5760 // http://www.unidata.ucar.edu/software/netcdf/docs/netcdf.html#Chunk-Cache 5774 // http://www.unidata.ucar.edu/software/netcdf/docs/netcdf.html#Chunk-Cache 5761 5775 // TODO: make sure this is okay. 5762 5776 CPLDebug( "GDAL_netCDF", 5763 5777 "DefVarDeflate( %d, %d ) nZlevel=%d", … … int netCDFDataset::DefVarDeflate( 5770 5784 5771 5785 // set chunking to be 1 for all dims, except X dim 5772 5786 // size_t chunksize[] = { 1, (size_t)nRasterXSize }; 5773 size_t chunksize[ MAX_NC_DIMS ]; 5787 vector<size_t> chunksizeStorage(MAX_NC_DIMS, 0); 5788 size_t * const chunksize = &chunksizeStorage[0]; 5789 5774 5790 int nd; 5775 5791 nc_inq_varndims( cdfid, nVarId, &nd ); 5776 5792 chunksize[0] = (size_t)1; … … int netCDFDataset::DefVarDeflate( 5778 5794 for( int i=2; i<nd; i++ ) chunksize[i] = (size_t)1; 5779 5795 chunksize[nd-1] = (size_t)nRasterXSize; 5780 5796 5781 CPLDebug( "GDAL_netCDF", 5797 CPLDebug( "GDAL_netCDF", 5782 5798 "DefVarDeflate() chunksize={%ld, %ld} chunkX=%ld nd=%d", 5783 5799 (long)chunksize[0], (long)chunksize[1], (long)chunksize[nd-1], nd ); 5784 5800 #ifdef NCDF_DEBUG 5785 for( int i=0; i<nd; i++ ) 5801 for( int i=0; i<nd; i++ ) 5786 5802 CPLDebug( "GDAL_netCDF","DefVarDeflate() chunk[%d]=%ld", i, chunksize[i] ); 5787 5803 #endif 5788 5804 5789 status = nc_def_var_chunking( cdfid, nVarId, 5805 status = nc_def_var_chunking( cdfid, nVarId, 5790 5806 NC_CHUNKED, chunksize ); 5791 5807 NCDF_ERR(status); 5792 5808 } … … static CPLErr NCDFGetAttr1( int nCdfId, int nVarId, const char *pszAttrName, 6295 6311 6296 6312 double dfValue = 0.0; 6297 6313 size_t m; 6298 char szTemp[ 256 ]; 6314 6315 const int szTempSize = 256; 6316 vector<char> szTempStorage(szTempSize, 0); 6317 char * const szTemp = &szTempStorage[0]; 6299 6318 6300 6319 switch (nAttrType) { 6301 6320 case NC_CHAR: … … static CPLErr NCDFGetAttr1( int nCdfId, int nVarId, const char *pszAttrName, 6311 6330 nc_get_att_schar( nCdfId, nVarId, pszAttrName, pscTemp ); 6312 6331 dfValue = static_cast<double>( pscTemp[0] ); 6313 6332 for(m=0; m < nAttrLen-1; m++) { 6314 snprintf( szTemp, s izeof(szTemp), "%d,", pscTemp[m] );6333 snprintf( szTemp, szTempSize, "%d,", pscTemp[m] ); 6315 6334 NCDFSafeStrcat(&pszAttrValue, szTemp, &nAttrValueSize); 6316 6335 } 6317 6336 snprintf( szTemp, sizeof(szTemp), "%d", pscTemp[m] ); … … static CPLErr NCDFGetAttr1( int nCdfId, int nVarId, const char *pszAttrName, 6328 6347 nc_get_att_uchar( nCdfId, nVarId, pszAttrName, pucTemp ); 6329 6348 dfValue = static_cast<double>( pucTemp[0] ); 6330 6349 for(m=0; m < nAttrLen-1; m++) { 6331 snprintf( szTemp, s izeof(szTemp), "%d,", pucTemp[m] );6350 snprintf( szTemp, szTempSize, "%d,", pucTemp[m] ); 6332 6351 NCDFSafeStrcat(&pszAttrValue, szTemp, &nAttrValueSize); 6333 6352 } 6334 snprintf( szTemp, s izeof(szTemp), "%d", pucTemp[m] );6353 snprintf( szTemp, szTempSize, "%d", pucTemp[m] ); 6335 6354 NCDFSafeStrcat(&pszAttrValue, szTemp, &nAttrValueSize); 6336 6355 CPLFree(pucTemp); 6337 6356 break; … … static CPLErr NCDFGetAttr1( int nCdfId, int nVarId, const char *pszAttrName, 6345 6364 nc_get_att_short( nCdfId, nVarId, pszAttrName, psTemp ); 6346 6365 dfValue = static_cast<double>( psTemp[0] ); 6347 6366 for(m=0; m < nAttrLen-1; m++) { 6348 snprintf( szTemp, s izeof(szTemp), "%hd,", psTemp[m] );6367 snprintf( szTemp, szTempSize, "%hd,", psTemp[m] ); 6349 6368 NCDFSafeStrcat(&pszAttrValue, szTemp, &nAttrValueSize); 6350 6369 } 6351 snprintf( szTemp, s izeof(szTemp), "%hd", psTemp[m] );6370 snprintf( szTemp, szTempSize, "%hd", psTemp[m] ); 6352 6371 NCDFSafeStrcat(&pszAttrValue, szTemp, &nAttrValueSize); 6353 6372 CPLFree(psTemp); 6354 6373 break; … … static CPLErr NCDFGetAttr1( int nCdfId, int nVarId, const char *pszAttrName, 6360 6379 nc_get_att_int( nCdfId, nVarId, pszAttrName, pnTemp ); 6361 6380 dfValue = static_cast<double>( pnTemp[0] ); 6362 6381 for(m=0; m < nAttrLen-1; m++) { 6363 snprintf( szTemp, s izeof(szTemp), "%d,", pnTemp[m] );6382 snprintf( szTemp, szTempSize, "%d,", pnTemp[m] ); 6364 6383 NCDFSafeStrcat(&pszAttrValue, szTemp, &nAttrValueSize); 6365 6384 } 6366 snprintf( szTemp, s izeof(szTemp), "%d", pnTemp[m] );6385 snprintf( szTemp, szTempSize, "%d", pnTemp[m] ); 6367 6386 NCDFSafeStrcat(&pszAttrValue, szTemp, &nAttrValueSize); 6368 6387 CPLFree(pnTemp); 6369 6388 break; … … static CPLErr NCDFGetAttr1( int nCdfId, int nVarId, const char *pszAttrName, 6376 6395 nc_get_att_float( nCdfId, nVarId, pszAttrName, pfTemp ); 6377 6396 dfValue = static_cast<double>( pfTemp[0] ); 6378 6397 for(m=0; m < nAttrLen-1; m++) { 6379 CPLsnprintf( szTemp, s izeof(szTemp), "%.8g,", pfTemp[m] );6398 CPLsnprintf( szTemp, szTempSize, "%.8g,", pfTemp[m] ); 6380 6399 NCDFSafeStrcat(&pszAttrValue, szTemp, &nAttrValueSize); 6381 6400 } 6382 CPLsnprintf( szTemp, s izeof(szTemp), "%.8g", pfTemp[m] );6401 CPLsnprintf( szTemp, szTempSize, "%.8g", pfTemp[m] ); 6383 6402 NCDFSafeStrcat(&pszAttrValue,szTemp, &nAttrValueSize); 6384 6403 CPLFree(pfTemp); 6385 6404 break; … … static CPLErr NCDFGetAttr1( int nCdfId, int nVarId, const char *pszAttrName, 6392 6411 nc_get_att_double( nCdfId, nVarId, pszAttrName, pdfTemp ); 6393 6412 dfValue = pdfTemp[0]; 6394 6413 for(m=0; m < nAttrLen-1; m++) { 6395 CPLsnprintf( szTemp, s izeof(szTemp), "%.16g,", pdfTemp[m] );6414 CPLsnprintf( szTemp, szTempSize, "%.16g,", pdfTemp[m] ); 6396 6415 NCDFSafeStrcat(&pszAttrValue, szTemp, &nAttrValueSize); 6397 6416 } 6398 CPLsnprintf( szTemp, s izeof(szTemp), "%.16g", pdfTemp[m] );6417 CPLsnprintf( szTemp, szTempSize, "%.16g", pdfTemp[m] ); 6399 6418 NCDFSafeStrcat(&pszAttrValue, szTemp, &nAttrValueSize); 6400 6419 CPLFree(pdfTemp); 6401 6420 break; … … static CPLErr NCDFPutAttr( int nCdfId, int nVarId, 6468 6487 /* strtof() is C89, which is not available in MSVC */ 6469 6488 /* see if we loose precision if we cast to float and write to char* */ 6470 6489 float fValue = float(dfValue); 6471 char szTemp[ 256 ]; 6472 CPLsnprintf( szTemp, sizeof(szTemp), "%.8g",fValue); 6490 const int szTempSize = 256; 6491 vector<char> szTempStorage(szTempSize, 0); 6492 char * const szTemp = &szTempStorage[0]; 6493 6494 CPLsnprintf( szTemp, szTempSize, "%.8g",fValue); 6473 6495 if ( EQUAL(szTemp, papszValues[i] ) ) 6474 6496 nTmpAttrType = NC_FLOAT; 6475 6497 else … … static CPLErr NCDFGet1DVar( int nCdfId, int nVarId, char **pszValue ) 6573 6595 if ( nVarLen > 1 && nVarType != NC_CHAR ) 6574 6596 NCDFSafeStrcat(&pszVarValue, "{", &nVarValueSize); 6575 6597 6598 const int szTempSize = 256; 6599 vector<char> szTempStorage(szTempSize, 0); 6600 char * const szTemp = &szTempStorage[0]; 6601 6576 6602 switch (nVarType) { 6577 6603 case NC_CHAR: 6578 6604 nc_get_vara_text( nCdfId, nVarId, start, count, pszVarValue ); … … static CPLErr NCDFGet1DVar( int nCdfId, int nVarId, char **pszValue ) 6584 6610 signed char *pscTemp = reinterpret_cast<signed char *> ( 6585 6611 CPLCalloc( nVarLen, sizeof( signed char ) ) ); 6586 6612 nc_get_vara_schar( nCdfId, nVarId, start, count, pscTemp ); 6587 char szTemp[ 256 ];6588 6613 size_t m = 0; 6589 6614 for( ; m < nVarLen-1; m++) { 6590 snprintf( szTemp, s izeof(szTemp), "%d,", pscTemp[m] );6615 snprintf( szTemp, szTempSize, "%d,", pscTemp[m] ); 6591 6616 NCDFSafeStrcat(&pszVarValue, szTemp, &nVarValueSize); 6592 6617 } 6593 6618 snprintf( szTemp, sizeof(szTemp), "%d", pscTemp[m] ); … … static CPLErr NCDFGet1DVar( int nCdfId, int nVarId, char **pszValue ) 6600 6625 short *psTemp = reinterpret_cast<short *> ( 6601 6626 CPLCalloc( nVarLen, sizeof( short ) ) ); 6602 6627 nc_get_vara_short( nCdfId, nVarId, start, count, psTemp ); 6603 char szTemp[ 256 ];6604 6628 size_t m = 0; 6605 6629 for( ; m < nVarLen-1; m++) { 6606 snprintf( szTemp, s izeof(szTemp), "%hd,", psTemp[m] );6630 snprintf( szTemp, szTempSize, "%hd,", psTemp[m] ); 6607 6631 NCDFSafeStrcat(&pszVarValue, szTemp, &nVarValueSize); 6608 6632 } 6609 6633 snprintf( szTemp, sizeof(szTemp), "%hd", psTemp[m] ); … … static CPLErr NCDFGet1DVar( int nCdfId, int nVarId, char **pszValue ) 6616 6640 int *pnTemp = reinterpret_cast<int *> ( 6617 6641 CPLCalloc( nVarLen, sizeof( int ) ) ); 6618 6642 nc_get_vara_int( nCdfId, nVarId, start, count, pnTemp ); 6619 char szTemp[ 256 ];6620 6643 size_t m = 0; 6621 6644 for( ; m < nVarLen-1; m++) { 6622 snprintf( szTemp, s izeof(szTemp), "%d,", pnTemp[m] );6645 snprintf( szTemp, szTempSize, "%d,", pnTemp[m] ); 6623 6646 NCDFSafeStrcat(&pszVarValue, szTemp, &nVarValueSize); 6624 6647 } 6625 6648 snprintf( szTemp, sizeof(szTemp), "%d", pnTemp[m] ); … … static CPLErr NCDFGet1DVar( int nCdfId, int nVarId, char **pszValue ) (this hunk was shorter than expected) 6632 6655 float *pfTemp = reinterpret_cast<float *> ( 6633 6656 CPLCalloc( nVarLen, sizeof( float ) ) ); 6634 6657 nc_get_vara_float( nCdfId, nVarId, start, count, pfTemp ); 6635 char szTemp[ 256 ];6636 6658 size_t m = 0; 6637 6659 for( ; m < nVarLen-1; m++) { 6638 CPLsnprintf( szTemp, s izeof(szTemp), "%.8g,", pfTemp[m] );6660 CPLsnprintf( szTemp, szTempSize, "%.8g,", pfTemp[m] ); 6639 6661 NCDFSafeStrcat(&pszVarValue, szTemp, &nVarValueSize); 6640 6662 } 6641 CPLsnprintf( szTemp, s izeof(szTemp), "%.8g", pfTemp[m] );6663 CPLsnprintf( szTemp, szTempSize, "%.8g", pfTemp[m] ); 6642 6664 NCDFSafeStrcat(&pszVarValue,szTemp, &nVarValueSize); 6643 6665 CPLFree(pfTemp); 6644 6666 break; … … static CPLErr NCDFGet1DVar( int nCdfId, int nVarId, char **pszValue ) 6648 6673 double *pdfTemp = reinterpret_cast<double *> ( 6649 6674 CPLCalloc( nVarLen, sizeof(double) ) ); 6650 6675 nc_get_vara_double( nCdfId, nVarId, start, count, pdfTemp ); 6651 char szTemp[ 256 ];6652 6676 size_t m = 0; 6653 6677 for( ; m < nVarLen-1; m++) { 6654 CPLsnprintf( szTemp, s izeof(szTemp), "%.16g,", pdfTemp[m] );6678 CPLsnprintf( szTemp, szTempSize, "%.16g,", pdfTemp[m] ); 6655 6679 NCDFSafeStrcat(&pszVarValue, szTemp, &nVarValueSize); 6656 6680 } 6657 CPLsnprintf( szTemp, s izeof(szTemp), "%.16g", pdfTemp[m] );6681 CPLsnprintf( szTemp, szTempSize, "%.16g", pdfTemp[m] ); 6658 6682 NCDFSafeStrcat(&pszVarValue, szTemp, &nVarValueSize); 6659 6683 CPLFree(pdfTemp); 6660 6684 break;
comment:4 by , 8 years ago
Looks reasonable, but I think that patterns like
char szTemp[ 256 ]; snprintf(szTemp, sizeof(szTemp), "%s#%s", pszGridMappingValue, pszParm);
would be better simplified as (one line instead of 4):
CPLString osTemp(pszGridMappingValue + CPLString("#") + pszParm);
comment:5 by , 8 years ago
Thanks! I was thinking that those could be simplified with C++ strings. I'll give it a try.
comment:6 by , 8 years ago
comment:8 by , 5 years ago
Milestone: | → closed_because_of_github_migration |
---|---|
Resolution: | → wontfix |
Status: | assigned → closed |
This ticket has been automatically closed because Trac is no longer used for GDAL bug tracking, since the project has migrated to GitHub. If you believe this ticket is still valid, you may file it to https://github.com/OSGeo/gdal/issues if it is not already reported there.
I'm not sure what stack consumers you've spotted, but one thing to be aware of is that some places can be performance critical and heap allocation with malloc() could slow down things.