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 Even Rouault, 9 years ago

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.

comment:2 by Kurt Schwehr, 9 years ago

Status: newassigned

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 Kurt Schwehr, 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.

  • frmts/netcdf/netcdfdataset.cpp

    a b  
    3535#include "gdal_frmts.h"
    3636#include "netcdfdataset.h"
    3737
    38 #include <map> //for NCDFWriteProjAttribs()
    3938#include <limits>
     39#include <map> //for NCDFWriteProjAttribs()
     40#include <vector>
     41
     42using std::vector;
    4043
    4144CPL_CVSID("$Id: netcdfdataset.cpp 32423 2015-12-21 12:33:17Z rouault $");
    4245
    netCDFRasterBand::netCDFRasterBand( netCDFDataset *poNCDFDS,  
    432435/* -------------------------------------------------------------------- */
    433436#ifdef NETCDF_HAS_NC4
    434437    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
    436441    status = nc_inq_format( cdfid, &nTmpFormat);
    437442    NetCDFFormatEnum eTmpFormat = static_cast<NetCDFFormatEnum>(nTmpFormat);
    438443    if( ( status == NC_NOERR ) && ( ( eTmpFormat == NCDF_FORMAT_NC4 ) ||
    CPLErr netCDFRasterBand::CreateBandMetadata( const int *paDimIds )  
    10161021        int nDims = 0;
    10171022        /* status = */ nc_inq_varndims( cdfid, nVarID, &nDims );
    10181023
    1019         char szMetaTemp[256];
     1024        vector<char> szMetaTempStorage(256, 0);
     1025        char * const szMetaTemp = &szMetaTempStorage[0];
    10201026        if( nDims == 1 ) {
    10211027            size_t count[1] = {1};
    10221028            size_t start[1] = {static_cast<size_t>(result)};
    CPLErr netCDFRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,  
    11961202/*      Locate X, Y and Z position in the array                         */
    11971203/* -------------------------------------------------------------------- */
    11981204
    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
    12011208    start[nBandXPos] = nBlockXOff * nBlockXSize;
    12021209
    12031210    // check y order
    CPLErr netCDFRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,  
    12231230      start[nBandYPos] = nBlockYOff * nBlockYSize;
    12241231    }
    12251232
    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];
    12281235
    12291236    edge[nBandXPos] = nBlockXSize;
    12301237    if ( ( start[nBandXPos] + edge[nBandXPos] ) > (size_t)nRasterXSize )
    CPLErr netCDFRasterBand::IWriteBlock( CPL_UNUSED int nBlockXOff,  
    13801387/*      Locate X, Y and Z position in the array                         */
    13811388/* -------------------------------------------------------------------- */
    13821389
    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];
    13851392
    13861393    start[nBandXPos] = 0;          // x dim can move around in array
    13871394    // check y order
    CPLErr netCDFRasterBand::IWriteBlock( CPL_UNUSED int nBlockXOff,  
    13911398        start[nBandYPos] = nBlockYOff; // y
    13921399    }
    13931400
    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];
    13961403
    1397     edge[nBandXPos] = nBlockXSize; 
     1404    edge[nBandXPos] = nBlockXSize;
    13981405    edge[nBandYPos] = 1;
    13991406
    14001407    if( nd == 3 ) {
    double netCDFDataset::FetchCopyParm( const char *pszGridMappingValue,  
    17011708                                     const char *pszParm, double dfDefault )
    17021709
    17031710{
    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);
    17061716    const char *pszValue = CSLFetchNameValue(papszMetadata, szTemp);
    17071717
    17081718    if( pszValue )
    double netCDFDataset::FetchCopyParm( const char *pszGridMappingValue,  
    17191729
    17201730char** netCDFDataset::FetchStandardParallels( const char *pszGridMappingValue )
    17211731{
    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);
    17251739    const char *pszValue = CSLFetchNameValue( papszMetadata, szTemp );
    17261740
    17271741    char **papszValues = NULL;
    int netCDFDataset::DefVarDeflate(  
    57575771    if ( eCompress == NCDF_COMPRESS_DEFLATE ) {
    57585772        // Must set chunk size to avoid huge performance hit (set bChunkingArg=TRUE)
    57595773        // 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
    57615775        // TODO: make sure this is okay.
    57625776        CPLDebug( "GDAL_netCDF",
    57635777                  "DefVarDeflate( %d, %d ) nZlevel=%d",
    int netCDFDataset::DefVarDeflate(  
    57705784
    57715785            // set chunking to be 1 for all dims, except X dim
    57725786            // 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
    57745790            int nd;
    57755791            nc_inq_varndims( cdfid, nVarId, &nd );
    57765792            chunksize[0] = (size_t)1;
    int netCDFDataset::DefVarDeflate(  
    57785794            for( int i=2; i<nd; i++ ) chunksize[i] = (size_t)1;
    57795795            chunksize[nd-1] = (size_t)nRasterXSize;
    57805796
    5781             CPLDebug( "GDAL_netCDF", 
     5797            CPLDebug( "GDAL_netCDF",
    57825798                      "DefVarDeflate() chunksize={%ld, %ld} chunkX=%ld nd=%d",
    57835799                      (long)chunksize[0], (long)chunksize[1], (long)chunksize[nd-1], nd );
    57845800#ifdef NCDF_DEBUG
    5785             for( int i=0; i<nd; i++ ) 
     5801            for( int i=0; i<nd; i++ )
    57865802                CPLDebug( "GDAL_netCDF","DefVarDeflate() chunk[%d]=%ld", i, chunksize[i] );
    57875803#endif
    57885804
    5789             status = nc_def_var_chunking( cdfid, nVarId,         
     5805            status = nc_def_var_chunking( cdfid, nVarId,
    57905806                                          NC_CHUNKED, chunksize );
    57915807            NCDF_ERR(status);
    57925808        }
    static CPLErr NCDFGetAttr1( int nCdfId, int nVarId, const char *pszAttrName,  
    62956311
    62966312    double dfValue = 0.0;
    62976313    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];
    62996318
    63006319    switch (nAttrType) {
    63016320        case NC_CHAR:
    static CPLErr NCDFGetAttr1( int nCdfId, int nVarId, const char *pszAttrName,  
    63116330            nc_get_att_schar( nCdfId, nVarId, pszAttrName, pscTemp );
    63126331            dfValue = static_cast<double>( pscTemp[0] );
    63136332            for(m=0; m < nAttrLen-1; m++) {
    6314                 snprintf( szTemp, sizeof(szTemp), "%d,", pscTemp[m] );
     6333                snprintf( szTemp, szTempSize, "%d,", pscTemp[m] );
    63156334                NCDFSafeStrcat(&pszAttrValue, szTemp, &nAttrValueSize);
    63166335            }
    63176336            snprintf( szTemp, sizeof(szTemp), "%d", pscTemp[m] );
    static CPLErr NCDFGetAttr1( int nCdfId, int nVarId, const char *pszAttrName,  
    63286347            nc_get_att_uchar( nCdfId, nVarId, pszAttrName, pucTemp );
    63296348            dfValue = static_cast<double>( pucTemp[0] );
    63306349            for(m=0; m < nAttrLen-1; m++) {
    6331                 snprintf( szTemp, sizeof(szTemp), "%d,", pucTemp[m] );
     6350                snprintf( szTemp, szTempSize, "%d,", pucTemp[m] );
    63326351                NCDFSafeStrcat(&pszAttrValue, szTemp, &nAttrValueSize);
    63336352            }
    6334             snprintf( szTemp, sizeof(szTemp), "%d", pucTemp[m] );
     6353            snprintf( szTemp, szTempSize, "%d", pucTemp[m] );
    63356354            NCDFSafeStrcat(&pszAttrValue, szTemp, &nAttrValueSize);
    63366355            CPLFree(pucTemp);
    63376356            break;
    static CPLErr NCDFGetAttr1( int nCdfId, int nVarId, const char *pszAttrName,  
    63456364            nc_get_att_short( nCdfId, nVarId, pszAttrName, psTemp );
    63466365            dfValue = static_cast<double>( psTemp[0] );
    63476366            for(m=0; m < nAttrLen-1; m++) {
    6348                 snprintf( szTemp, sizeof(szTemp), "%hd,", psTemp[m] );
     6367                snprintf( szTemp, szTempSize, "%hd,", psTemp[m] );
    63496368                NCDFSafeStrcat(&pszAttrValue, szTemp, &nAttrValueSize);
    63506369            }
    6351             snprintf( szTemp, sizeof(szTemp), "%hd", psTemp[m] );
     6370            snprintf( szTemp, szTempSize, "%hd", psTemp[m] );
    63526371            NCDFSafeStrcat(&pszAttrValue, szTemp, &nAttrValueSize);
    63536372            CPLFree(psTemp);
    63546373            break;
    static CPLErr NCDFGetAttr1( int nCdfId, int nVarId, const char *pszAttrName,  
    63606379            nc_get_att_int( nCdfId, nVarId, pszAttrName, pnTemp );
    63616380            dfValue = static_cast<double>( pnTemp[0] );
    63626381            for(m=0; m < nAttrLen-1; m++) {
    6363                 snprintf( szTemp, sizeof(szTemp), "%d,", pnTemp[m] );
     6382                snprintf( szTemp, szTempSize, "%d,", pnTemp[m] );
    63646383                NCDFSafeStrcat(&pszAttrValue, szTemp, &nAttrValueSize);
    63656384            }
    6366             snprintf( szTemp, sizeof(szTemp), "%d", pnTemp[m] );
     6385            snprintf( szTemp, szTempSize, "%d", pnTemp[m] );
    63676386            NCDFSafeStrcat(&pszAttrValue, szTemp, &nAttrValueSize);
    63686387            CPLFree(pnTemp);
    63696388            break;
    static CPLErr NCDFGetAttr1( int nCdfId, int nVarId, const char *pszAttrName,  
    63766395            nc_get_att_float( nCdfId, nVarId, pszAttrName, pfTemp );
    63776396            dfValue = static_cast<double>( pfTemp[0] );
    63786397            for(m=0; m < nAttrLen-1; m++) {
    6379                 CPLsnprintf( szTemp, sizeof(szTemp), "%.8g,", pfTemp[m] );
     6398                CPLsnprintf( szTemp, szTempSize, "%.8g,", pfTemp[m] );
    63806399                NCDFSafeStrcat(&pszAttrValue, szTemp, &nAttrValueSize);
    63816400            }
    6382             CPLsnprintf( szTemp, sizeof(szTemp), "%.8g", pfTemp[m] );
     6401            CPLsnprintf( szTemp, szTempSize, "%.8g", pfTemp[m] );
    63836402            NCDFSafeStrcat(&pszAttrValue,szTemp, &nAttrValueSize);
    63846403            CPLFree(pfTemp);
    63856404            break;
    static CPLErr NCDFGetAttr1( int nCdfId, int nVarId, const char *pszAttrName,  
    63926411            nc_get_att_double( nCdfId, nVarId, pszAttrName, pdfTemp );
    63936412            dfValue = pdfTemp[0];
    63946413            for(m=0; m < nAttrLen-1; m++) {
    6395                 CPLsnprintf( szTemp, sizeof(szTemp), "%.16g,", pdfTemp[m] );
     6414                CPLsnprintf( szTemp, szTempSize, "%.16g,", pdfTemp[m] );
    63966415                NCDFSafeStrcat(&pszAttrValue, szTemp, &nAttrValueSize);
    63976416            }
    6398             CPLsnprintf( szTemp, sizeof(szTemp), "%.16g", pdfTemp[m] );
     6417            CPLsnprintf( szTemp, szTempSize, "%.16g", pdfTemp[m] );
    63996418            NCDFSafeStrcat(&pszAttrValue, szTemp, &nAttrValueSize);
    64006419            CPLFree(pdfTemp);
    64016420            break;
    static CPLErr NCDFPutAttr( int nCdfId, int nVarId,  
    64686487                /* strtof() is C89, which is not available in MSVC */
    64696488                /* see if we loose precision if we cast to float and write to char* */
    64706489                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);
    64736495                if ( EQUAL(szTemp, papszValues[i] ) )
    64746496                    nTmpAttrType = NC_FLOAT;
    64756497                else
    static CPLErr NCDFGet1DVar( int nCdfId, int nVarId, char **pszValue )  
    65736595    if ( nVarLen > 1 && nVarType != NC_CHAR )   
    65746596        NCDFSafeStrcat(&pszVarValue, "{", &nVarValueSize);
    65756597
     6598    const int szTempSize = 256;
     6599    vector<char> szTempStorage(szTempSize, 0);
     6600    char * const szTemp = &szTempStorage[0];
     6601
    65766602    switch (nVarType) {
    65776603        case NC_CHAR:
    65786604            nc_get_vara_text( nCdfId, nVarId, start, count, pszVarValue );
    static CPLErr NCDFGet1DVar( int nCdfId, int nVarId, char **pszValue )  
    65846610            signed char *pscTemp = reinterpret_cast<signed char *> (
    65856611                CPLCalloc( nVarLen, sizeof( signed char ) ) );
    65866612            nc_get_vara_schar( nCdfId, nVarId, start, count, pscTemp );
    6587             char szTemp[ 256 ];
    65886613            size_t m = 0;
    65896614            for( ; m < nVarLen-1; m++) {
    6590                 snprintf( szTemp, sizeof(szTemp), "%d,", pscTemp[m] );
     6615                snprintf( szTemp, szTempSize, "%d,", pscTemp[m] );
    65916616                NCDFSafeStrcat(&pszVarValue, szTemp, &nVarValueSize);
    65926617            }
    65936618            snprintf( szTemp, sizeof(szTemp), "%d", pscTemp[m] );
    static CPLErr NCDFGet1DVar( int nCdfId, int nVarId, char **pszValue )  
    66006625            short *psTemp = reinterpret_cast<short *> (
    66016626                CPLCalloc( nVarLen, sizeof( short ) ) );
    66026627            nc_get_vara_short( nCdfId, nVarId, start, count, psTemp );
    6603             char szTemp[ 256 ];
    66046628            size_t m = 0;
    66056629            for( ; m < nVarLen-1; m++) {
    6606                 snprintf( szTemp, sizeof(szTemp), "%hd,", psTemp[m] );
     6630                snprintf( szTemp, szTempSize, "%hd,", psTemp[m] );
    66076631                NCDFSafeStrcat(&pszVarValue, szTemp, &nVarValueSize);
    66086632            }
    66096633            snprintf( szTemp, sizeof(szTemp),  "%hd", psTemp[m] );
    static CPLErr NCDFGet1DVar( int nCdfId, int nVarId, char **pszValue )  
    66166640            int *pnTemp = reinterpret_cast<int *> (
    66176641                CPLCalloc( nVarLen, sizeof( int ) ) );
    66186642            nc_get_vara_int( nCdfId, nVarId, start, count, pnTemp );
    6619             char szTemp[ 256 ];
    66206643            size_t m = 0;
    66216644            for( ; m < nVarLen-1; m++) {
    6622                 snprintf( szTemp, sizeof(szTemp), "%d,", pnTemp[m] );
     6645                snprintf( szTemp, szTempSize, "%d,", pnTemp[m] );
    66236646                NCDFSafeStrcat(&pszVarValue, szTemp, &nVarValueSize);
    66246647            }
    66256648            snprintf( szTemp, sizeof(szTemp), "%d", pnTemp[m] );
    static CPLErr NCDFGet1DVar( int nCdfId, int nVarId, char **pszValue ) (this hunk was shorter than expected)  
    66326655            float *pfTemp = reinterpret_cast<float *> (
    66336656                CPLCalloc( nVarLen, sizeof( float ) ) );
    66346657            nc_get_vara_float( nCdfId, nVarId, start, count, pfTemp );
    6635             char szTemp[ 256 ];
    66366658            size_t m = 0;
    66376659            for( ; m < nVarLen-1; m++) {
    6638                 CPLsnprintf( szTemp, sizeof(szTemp), "%.8g,", pfTemp[m] );
     6660                CPLsnprintf( szTemp, szTempSize, "%.8g,", pfTemp[m] );
    66396661                NCDFSafeStrcat(&pszVarValue, szTemp, &nVarValueSize);
    66406662            }
    6641             CPLsnprintf( szTemp, sizeof(szTemp), "%.8g", pfTemp[m] );
     6663            CPLsnprintf( szTemp, szTempSize, "%.8g", pfTemp[m] );
    66426664            NCDFSafeStrcat(&pszVarValue,szTemp, &nVarValueSize);
    66436665            CPLFree(pfTemp);
    66446666            break;
    static CPLErr NCDFGet1DVar( int nCdfId, int nVarId, char **pszValue )  
    66486673            double *pdfTemp = reinterpret_cast<double *> (
    66496674                CPLCalloc( nVarLen, sizeof(double) ) );
    66506675            nc_get_vara_double( nCdfId, nVarId, start, count, pdfTemp );
    6651             char szTemp[ 256 ];
    66526676            size_t m = 0;
    66536677            for( ; m < nVarLen-1; m++) {
    6654                 CPLsnprintf( szTemp, sizeof(szTemp), "%.16g,", pdfTemp[m] );
     6678                CPLsnprintf( szTemp, szTempSize, "%.16g,", pdfTemp[m] );
    66556679                NCDFSafeStrcat(&pszVarValue, szTemp, &nVarValueSize);
    66566680            }
    6657             CPLsnprintf( szTemp, sizeof(szTemp), "%.16g", pdfTemp[m] );
     6681            CPLsnprintf( szTemp, szTempSize, "%.16g", pdfTemp[m] );
    66586682            NCDFSafeStrcat(&pszVarValue, szTemp, &nVarValueSize);
    66596683            CPLFree(pdfTemp);
    66606684            break;
Last edited 8 years ago by Kurt Schwehr (previous) (diff)

comment:4 by Even Rouault, 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 Kurt Schwehr, 8 years ago

Thanks! I was thinking that those could be simplified with C++ strings. I'll give it a try.

comment:6 by Kurt Schwehr, 8 years ago

r33176 r33175 r33179 For gdalexif EXIFExtractMetadata() char szTemp[MAXSTRINGLENGTH+1];

comment:7 by Kurt Schwehr, 8 years ago

r33191 for hdf5dataset.cpp

comment:8 by Even Rouault, 5 years ago

Milestone: closed_because_of_github_migration
Resolution: wontfix
Status: assignedclosed

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.

Note: See TracTickets for help on using tickets.