Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expression variables are calculated too often #60112

Open
2 tasks done
Joonalai opened this issue Jan 10, 2025 · 4 comments
Open
2 tasks done

Expression variables are calculated too often #60112

Joonalai opened this issue Jan 10, 2025 · 4 comments
Labels
Bug Either a bug report, or a bug fix. Let's hope for the latter! Feedback Waiting on the submitter for answers

Comments

@Joonalai
Copy link
Contributor

Joonalai commented Jan 10, 2025

What is the bug or the crash?

When trying to figure out why QGIS gets frozen and really slow with more than 200 layers, I noticed expression variables are calculated really often.

Steps to reproduce the issue

To reproduce the issue it's easiest to add log line to QgsExpressionContextUtils::layerScope method and then do following steps:

  1. Add layer to the project
  2. Digitize one feature
  3. Move map canvas
  4. Calculate lines on the log panel

These simple steps produce 85 lines for memory polygon layer, 123 lines for gpkg polygon layer and 226 lines for PostGIS layer.

too-many-calculations

Versions

Version details <style type="text/css"> p, li { white-space: pre-wrap; } </style>
QGIS version 3.40.2-Bratislava
QGIS code revision 14826ca
 
Libraries
Qt version 5.15.13
Python version 3.12.3
GDAL/OGR version 3.8.4
PROJ version 9.4.0
EPSG Registry database version v11.004 (2024-02-24)
GEOS version 3.12.1-CAPI-1.18.1
SQLite version 3.45.1
PostgreSQL client version 16.6 (Ubuntu 16.6-0ubuntu0.24.04.1)
SpatiaLite version 5.1.0
QWT version 6.1.4
QScintilla2 version 2.14.1
OS version Ubuntu 24.04.1 LTS
 
Active Python plugins
db_manager 0.1.20
MetaSearch 0.3.6
processing 2.12.99
grassprovider 2.12.99
QGIS version 3.40.2-Bratislava QGIS code revision [14826ca](https://github.com/qgis/QGIS/commit/14826ca1e4a)

Libraries
Qt version
5.15.13
Python version
3.12.3
GDAL/OGR version
3.8.4
PROJ version
9.4.0
EPSG Registry database version
v11.004 (2024-02-24)
GEOS version
3.12.1-CAPI-1.18.1
SQLite version
3.45.1
PostgreSQL client version
16.6 (Ubuntu 16.6-0ubuntu0.24.04.1)
SpatiaLite version
5.1.0
QWT version
6.1.4
QScintilla2 version
2.14.1
OS version
Ubuntu 24.04.1 LTS

Active Python plugins
db_manager
0.1.20
MetaSearch
0.3.6
processing
2.12.99
grassprovider
2.12.99

Supported QGIS version

  • I'm running a supported QGIS version according to the roadmap.

New profile

Additional context

Maybe some kind of caching should be used to limit amount of times variables are calculated?

@Joonalai Joonalai added the Bug Either a bug report, or a bug fix. Let's hope for the latter! label Jan 10, 2025
nyalldawson added a commit to nyalldawson/QGIS that referenced this issue Jan 31, 2025
We already have set the layer scope for ALL layer types in
the map renderer job preparation, so there's no need to
add another layer scope in the vector layer renderer

Refs qgis#60112
@nyalldawson
Copy link
Collaborator

This is possibly caused by a plugin or some other local configuration issue -- on my testing I only see this method called twice per layer per map draw (or once after #60367 is merged)

@nyalldawson nyalldawson added the Feedback Waiting on the submitter for answers label Jan 31, 2025
nyalldawson added a commit that referenced this issue Jan 31, 2025
We already have set the layer scope for ALL layer types in
the map renderer job preparation, so there's no need to
add another layer scope in the vector layer renderer

Refs #60112
@Joonalai
Copy link
Contributor Author

I tried with your changes with newest master (9f7f9d7). I added the log line qDebug() << "layerScope: " << layer->name(); to

//add variables defined in layer properties

and with single GPKG layer and now there is still 41 calls for a single polygon memory layer after doing the steps in the issue.

Image

I am using clean profile with no plugins or other configuration and I develop QGIS through Distrobox using official qgis3-build-deps image as a base image, so I think there should not be anything in my configuration causing this.

Version information <style type="text/css"> p, li { white-space: pre-wrap; } </style>
QGIS version 3.41.0-Master
QGIS code revision 9f7f9d7
 
Libraries
Qt version 5.15.3
Python version 3.10.12
GDAL/OGR version 3.4.1
PROJ version 8.2.1
EPSG Registry database version v10.041 (2021-12-03)
GEOS version 3.10.2-CAPI-1.16.0
SQLite version 3.37.2
PDAL version 2.3.0
PostgreSQL client version unknown
SpatiaLite version 5.0.1
QWT version 6.1.4
QScintilla2 version 2.11.6
OS version Ubuntu 22.04.3 LTS
This copy of QGIS writes debugging output.
 
Active Python plugins
db_manager 0.1.20
MetaSearch 0.3.6
processing 2.12.99
grassprovider 2.12.99
QGIS version 3.41.0-Master QGIS code revision [9f7f9d7](https://github.com/qgis/QGIS/commit/9f7f9d70bce)

Libraries
Qt version
5.15.3
Python version
3.10.12
GDAL/OGR version
3.4.1
PROJ version
8.2.1
EPSG Registry database version
v10.041 (2021-12-03)
GEOS version
3.10.2-CAPI-1.16.0
SQLite version
3.37.2
PDAL version
2.3.0
PostgreSQL client version
unknown
SpatiaLite version
5.0.1
QWT version
6.1.4
QScintilla2 version
2.11.6
OS version
Ubuntu 22.04.3 LTS
This copy of QGIS writes debugging output.

Active Python plugins
db_manager
0.1.20
MetaSearch
0.3.6
processing
2.12.99
grassprovider
2.12.99

@nyalldawson
Copy link
Collaborator

@Joonalai I can't explain that -- maybe try a debug build and set a breakpoint and see what's calling it

@Joonalai
Copy link
Contributor Author

Here is a callers.log that contains call stacks for each call.

I used this code to get these:

Code
void logCallStack() {
  const int maxFrames = 50;
  void* framePointers[maxFrames];

  // Capture stack frames
  int frameCount = backtrace(framePointers, maxFrames);

  // Transform frame addresses into readable symbols
  char** symbolList = backtrace_symbols(framePointers, frameCount);

  std::cerr << "Call stack:\n";
  for (int i = 0; i < frameCount; i++) {
    std::string symbol = symbolList[i]; // Convert to a std::string for manipulation

    // Extract between the parentheses (demangling happens here)
    size_t begin = symbol.find('(');
    size_t plus = symbol.find('+', begin);
    if (begin != std::string::npos && plus != std::string::npos) {
      std::string mangledName = symbol.substr(begin + 1, plus - begin - 1); // Extract mangled name
      int status;
      char* demangledName = abi::__cxa_demangle(mangledName.c_str(), nullptr, nullptr, &status);

      if (status == 0 && demangledName != nullptr) {
        if (*demangledName != '\0') // Ensure the demangled name is not empty
          std::cerr << "    " << demangledName << std::endl; // Print demangled name
      } else {
        if (!mangledName.empty()) // Ensure the mangled name is not empty
          std::cerr << "    " << mangledName << std::endl; // If demangling fails, print mangled name
      }

      std::free(demangledName); // Free memory allocated by __cxa_demangle
    }
  }

  std::free(symbolList); // Cleanup
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug Either a bug report, or a bug fix. Let's hope for the latter! Feedback Waiting on the submitter for answers
Projects
None yet
Development

No branches or pull requests

2 participants